@runnerpro/backend 1.34.1 → 1.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,8 +19,8 @@ const ffmpegUtils_1 = require("./ffmpegUtils");
19
19
  const image_1 = require("./image");
20
20
  const audio_1 = require("./audio");
21
21
  const index_1 = require("../err/index");
22
- // ✅ La pista se manda como LINEAR16, y con un encoding declarado de verdad Speech-to-Text
23
- // aplica su límite de 60s de forma estricta (ver el aviso en audio.ts). Se recorta con margen.
22
+ // ✅ La pista se recorta para acotar coste y latencia del análisis de un vídeo de chat; el motor de
23
+ // transcripción (Azure Speech) admitiría mucho más.
24
24
  const AUDIO_TRACK_MAX_SECONDS = 55;
25
25
  const VIDEO_FRAME_PROMPT = `Esto es un fotograma extraído de un vídeo enviado en un chat de entrenamiento.
26
26
  Describe lo que se ve de forma directa en un solo párrafo continuo, sin introducciones ni listas.
@@ -89,7 +89,7 @@ const formatDuration = (seconds) => {
89
89
  * // "Vídeo de 12 s. Imagen: corredor de perfil sobre cinta... Audio: mira cómo apoyo el talón..."
90
90
  * ```
91
91
  */
92
- const describeVideo = (fileBuffer, mimetype, filename) => __awaiter(void 0, void 0, void 0, function* () {
92
+ const describeVideo = (fileBuffer, mimetype, filename, contexto) => __awaiter(void 0, void 0, void 0, function* () {
93
93
  try {
94
94
  return yield (0, ffmpegUtils_1.withTempDir)((dir) => __awaiter(void 0, void 0, void 0, function* () {
95
95
  // ffmpeg detecta el formato por contenido, así que la extensión solo es cosmética
@@ -123,7 +123,7 @@ const describeVideo = (fileBuffer, mimetype, filename) => __awaiter(void 0, void
123
123
  const [imageText, audioText] = yield Promise.all([
124
124
  frameBuffer ? (0, image_1.describeImage)(frameBuffer, 'image/jpeg', VIDEO_FRAME_PROMPT) : Promise.resolve(null),
125
125
  // ⭐ La pista ya sale de ffmpeg en WAV mono 16 kHz, así que no hay que volver a convertirla
126
- audioBuffer ? (0, audio_1.transcribeWav16k)(audioBuffer) : Promise.resolve(null),
126
+ audioBuffer ? (0, audio_1.transcribeWav16k)(audioBuffer, contexto) : Promise.resolve(null),
127
127
  ]);
128
128
  const header = `Vídeo${formatDuration(duration) ? ` de ${formatDuration(duration)}` : ''}`;
129
129
  const parts = [];
@@ -22,8 +22,9 @@ import { saveDoneStructuraWorkout } from './workout/estructuraWorkout';
22
22
  import { getZone } from './workout/paceZone';
23
23
  import { saveResponseTime } from './chat/saveResponseTime';
24
24
  import { updateSenderView } from './chat/api/conversation';
25
- import { transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, analyzeFile, processMediaFile, reprocessRecentMedia } from './mediaProcessing';
25
+ import { transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, analyzeFile, processMediaFile, reprocessRecentMedia, reprocessMediaByIds, corregirTranscripcion, GLOSARIO_RUNNING, MARCADOR_SIN_VOZ, MARCADOR_NO_TRANSCRITO, MARCADORES_AUDIO } from './mediaProcessing';
26
+ export type { ContextoTranscripcion } from './mediaProcessing';
26
27
  import { generateObject, generateText, createGoogleModel, createGoogleModelFromString, createBedrockModelFromString, createAzureModelFromString, createModelFromString, runWithCostTracking, runWithModels, MODEL_TIER, AI_MODELS, GOOGLE_MODELS, AZURE_PREFIX, AZURE_GPT_5_5_DEPLOYMENT, AZURE_GPT_5_6_SOL_DEPLOYMENT, AZURE_GPT_5_6_TERRA_DEPLOYMENT, AZURE_GPT_5_6_LUNA_DEPLOYMENT, AZURE_GPT_5_4_MINI_DEPLOYMENT, AZURE_GPT_5_4_NANO_DEPLOYMENT, AZURE_DEEPSEEK_V4_PRO_DEPLOYMENT, AZURE_DEEPSEEK_V4_FLASH_DEPLOYMENT, AZURE_GPT_5_5, AZURE_GPT_5_6_SOL, AZURE_GPT_5_6_TERRA, AZURE_GPT_5_6_LUNA, AZURE_GPT_5_4_MINI, AZURE_GPT_5_4_NANO, AZURE_DEEPSEEK_V4_PRO, AZURE_DEEPSEEK_V4_FLASH, AZURE_PRIMARY_MODELS, AZURE_FALLBACK_MODELS, PRODUCTION_MODELS, FALLBACK_MODELS, BEDROCK_CLAUDE_OPUS, BEDROCK_CLAUDE_SONNET, BEDROCK_CLAUDE_OPUS_4_5, BEDROCK_CLAUDE_OPUS_4_1, BEDROCK_CLAUDE_SONNET_4_5, BEDROCK_CLAUDE_SONNET_4, BEDROCK_CLAUDE_HAIKU, AISTUDIO_PREFIX, MODEL_PRICING, calculateCost } from './prompt';
27
28
  export { Storage as StorageAzure, Contenedor, Archivo, urlPublica, TIPO_POR_DEFECTO, } from './almacenamiento';
28
- export { sendNotification, sleep, query, queryWithClient, longRunningQuery, batchQuery, toPgArray, pool, sendMail, err, fetchIA, notifySlack, CHANNEL_SLACK, translate, LANGUAGES, useTranslation, getExerciseTranslatedDescription, chat, chatApi, chatExposed, getCountNotificaciones, notionGetUsers, notionGetDatabase, notionAddPage, notionEditPage, NOTION_DATABASES_ID, readSheet, findCellByValue, writeSheet, appendSheet, getNumberByLetter, getLetter, reduceSizeImage, generateShareMap, getDefaultWorkoutImage, sendWorkoutToWatch, getPlanificacionPrueba7dias, saveWorkoutAplication, saveWorkoutLaps, evaluateAchievements, evaluateAchievementsBounded, getUnlockedAchievements, computeStreakStats, saveDoneStructuraWorkout, getZone, saveResponseTime, updateSenderView, transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, analyzeFile, processMediaFile, reprocessRecentMedia, generateObject, generateText, createGoogleModel, createGoogleModelFromString, createBedrockModelFromString, createAzureModelFromString, createModelFromString, runWithCostTracking, runWithModels, MODEL_TIER, AI_MODELS, GOOGLE_MODELS, AZURE_PREFIX, AZURE_GPT_5_5_DEPLOYMENT, AZURE_GPT_5_6_SOL_DEPLOYMENT, AZURE_GPT_5_6_TERRA_DEPLOYMENT, AZURE_GPT_5_6_LUNA_DEPLOYMENT, AZURE_GPT_5_4_MINI_DEPLOYMENT, AZURE_GPT_5_4_NANO_DEPLOYMENT, AZURE_DEEPSEEK_V4_PRO_DEPLOYMENT, AZURE_DEEPSEEK_V4_FLASH_DEPLOYMENT, AZURE_GPT_5_5, AZURE_GPT_5_6_SOL, AZURE_GPT_5_6_TERRA, AZURE_GPT_5_6_LUNA, AZURE_GPT_5_4_MINI, AZURE_GPT_5_4_NANO, AZURE_DEEPSEEK_V4_PRO, AZURE_DEEPSEEK_V4_FLASH, AZURE_PRIMARY_MODELS, AZURE_FALLBACK_MODELS, PRODUCTION_MODELS, FALLBACK_MODELS, BEDROCK_CLAUDE_OPUS, BEDROCK_CLAUDE_SONNET, BEDROCK_CLAUDE_OPUS_4_5, BEDROCK_CLAUDE_OPUS_4_1, BEDROCK_CLAUDE_SONNET_4_5, BEDROCK_CLAUDE_SONNET_4, BEDROCK_CLAUDE_HAIKU, AISTUDIO_PREFIX, MODEL_PRICING, calculateCost, };
29
+ export { sendNotification, sleep, query, queryWithClient, longRunningQuery, batchQuery, toPgArray, pool, sendMail, err, fetchIA, notifySlack, CHANNEL_SLACK, translate, LANGUAGES, useTranslation, getExerciseTranslatedDescription, chat, chatApi, chatExposed, getCountNotificaciones, notionGetUsers, notionGetDatabase, notionAddPage, notionEditPage, NOTION_DATABASES_ID, readSheet, findCellByValue, writeSheet, appendSheet, getNumberByLetter, getLetter, reduceSizeImage, generateShareMap, getDefaultWorkoutImage, sendWorkoutToWatch, getPlanificacionPrueba7dias, saveWorkoutAplication, saveWorkoutLaps, evaluateAchievements, evaluateAchievementsBounded, getUnlockedAchievements, computeStreakStats, saveDoneStructuraWorkout, getZone, saveResponseTime, updateSenderView, transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, analyzeFile, processMediaFile, reprocessRecentMedia, reprocessMediaByIds, corregirTranscripcion, GLOSARIO_RUNNING, MARCADOR_SIN_VOZ, MARCADOR_NO_TRANSCRITO, MARCADORES_AUDIO, generateObject, generateText, createGoogleModel, createGoogleModelFromString, createBedrockModelFromString, createAzureModelFromString, createModelFromString, runWithCostTracking, runWithModels, MODEL_TIER, AI_MODELS, GOOGLE_MODELS, AZURE_PREFIX, AZURE_GPT_5_5_DEPLOYMENT, AZURE_GPT_5_6_SOL_DEPLOYMENT, AZURE_GPT_5_6_TERRA_DEPLOYMENT, AZURE_GPT_5_6_LUNA_DEPLOYMENT, AZURE_GPT_5_4_MINI_DEPLOYMENT, AZURE_GPT_5_4_NANO_DEPLOYMENT, AZURE_DEEPSEEK_V4_PRO_DEPLOYMENT, AZURE_DEEPSEEK_V4_FLASH_DEPLOYMENT, AZURE_GPT_5_5, AZURE_GPT_5_6_SOL, AZURE_GPT_5_6_TERRA, AZURE_GPT_5_6_LUNA, AZURE_GPT_5_4_MINI, AZURE_GPT_5_4_NANO, AZURE_DEEPSEEK_V4_PRO, AZURE_DEEPSEEK_V4_FLASH, AZURE_PRIMARY_MODELS, AZURE_FALLBACK_MODELS, PRODUCTION_MODELS, FALLBACK_MODELS, BEDROCK_CLAUDE_OPUS, BEDROCK_CLAUDE_SONNET, BEDROCK_CLAUDE_OPUS_4_5, BEDROCK_CLAUDE_OPUS_4_1, BEDROCK_CLAUDE_SONNET_4_5, BEDROCK_CLAUDE_SONNET_4, BEDROCK_CLAUDE_HAIKU, AISTUDIO_PREFIX, MODEL_PRICING, calculateCost, };
29
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,13 @@
1
1
  /// <reference types="node" />
2
- declare const AUDIO_ENCODING_MAP: Record<string, string>;
3
- declare const SYNC_MAX_SECONDS = 55;
2
+ import { ContextoTranscripcion } from './correccionTranscripcion';
3
+ declare const TRANSCRIPTION_MAX_SECONDS = 600;
4
+ declare const MAX_CARACTERES_POR_SEGUNDO = 25;
5
+ declare const MARCADOR_SIN_VOZ = "[Audio sin voz reconocible]";
6
+ declare const MARCADOR_NO_TRANSCRITO = "[Audio no transcrito]";
7
+ declare const MARCADOR_ANTIGUO = "[Audio sin contenido reconocible]";
8
+ declare const MARCADORES_AUDIO: string[];
4
9
  /**
5
- * Transcribe con un modelo multimodal de Google. Es la red que recoge lo que Speech-to-Text
6
- * no reconoce y, sobre todo, los audios de más de 60s, que el modo síncrono no admite.
7
- *
8
- * @param wavBuffer - Buffer WAV mono 16 kHz
9
- * @returns Promise<string | null> - Transcripción, o null si no hay voz
10
- */
11
- declare const transcribeWithModel: (wavBuffer: Buffer) => Promise<string | null>;
12
- /**
13
- * Convierte cualquier audio al formato que espera Speech-to-Text (WAV PCM mono 16 kHz)
10
+ * Convierte cualquier audio a WAV PCM mono 16 kHz, recortado a 10 minutos
14
11
  *
15
12
  * @param fileBuffer - Buffer del audio original
16
13
  * @param filename - Nombre original del archivo
@@ -23,41 +20,39 @@ declare const convertToWav16k: (fileBuffer: Buffer, filename?: string) => Promis
23
20
  /**
24
21
  * Transcribe una nota de voz.
25
22
  *
26
- * El audio se normaliza a WAV mono 16 kHz y luego se elige motor por duración:
27
- * - hasta 55s → Speech-to-Text, que es barato y preciso.
28
- * - más de 55s modelo multimodal, porque `recognize` no admite audios más largos y
29
- * `longRunningRecognize` exige subir el archivo a GCS antes.
30
- * - si Speech-to-Text no reconoce nada, se reintenta con el modelo antes de darlo por perdido.
23
+ * Cadena, toda en Azure: medir duración y volumen con ffmpeg si no hay voz, marcador sin llamar
24
+ * a nadieAzure AI Speech con el locale del cliente y una lista de frases (nombres + jerga) →
25
+ * si falla o no oye nada, gpt-4o-mini-transcribe sin prompt si el texto es físicamente imposible
26
+ * (más de 25 caracteres por segundo), marcador → corrección de jerga y nombres con el modelo LITE
27
+ * detrás de un filtro determinista.
31
28
  *
32
- * ⚠️ El orden importa y no es intercambiable. Medido sobre notas de voz reales de producción
33
- * que hoy acaban en '[Audio sin contenido reconocible]':
34
- * - mandar el AAC crudo declarando 'MP3' (lo que se hacía): 0 de 14 recuperadas.
35
- * - convertir a WAV y declarar LINEAR16: 13 de 14 (la que falla es de 81s).
36
- * - modelo multimodal: 14 de 14.
37
- * Y a la inversa, convertir a WAV SIN respetar el límite de 55s rompe los audios largos que hoy
38
- * sí funcionan (4 de 4 medidos): con LINEAR16 la API deduce la duración exacta y los rechaza,
39
- * mientras que con un códec comprimido declarado se saltaba esa comprobación.
29
+ * ⚠️ Medido sobre 74 notas de voz reales (06-sep-2026): Google Speech-to-Text cambiaba a inglés al
30
+ * azar en 2 de 74 (la identificación multi-idioma) y dejaba vacíos 3 audios con voz; los modelos
31
+ * generativos (Gemini, gpt-audio, transcribe con prompt) escribían una nota entera ante clips en
32
+ * silencio. Azure Speech: 0 invenciones, 0 vacíos con voz, p50 1,2 s.
40
33
  *
41
- * @param fileBuffer - Buffer del archivo de audio
34
+ * @param fileBuffer - Buffer del archivo de audio (aac, m4a, mp3, wav, ogg…)
42
35
  * @param mimetype - Tipo MIME del archivo (ej: 'audio/aac', 'audio/x-m4a')
43
36
  * @param filename - Nombre original del archivo
44
- * @returns Promise<string> - Transcripción del audio
37
+ * @param contexto - Idioma, nombres y últimos mensajes del cliente (opcional)
38
+ * @returns Promise<string> - Transcripción, o un marcador si no hay voz o no se pudo transcribir
45
39
  *
46
40
  * @example
47
41
  * ```typescript
48
- * const transcription = await transcribeAudio(audioBuffer, 'audio/aac', 'audio.aac');
49
- * // Resultado: "Hola, quería comentarte que hoy me duele un poco la rodilla..."
42
+ * const transcription = await transcribeAudio(audioBuffer, 'audio/aac', 'audio.aac', { idioma: 'es', nombres: ['Ana', 'Rubén'] });
43
+ * // Resultado: "Hola Rubén, quería comentarte que hoy me duele un poco la rodilla..."
50
44
  * ```
51
45
  */
52
- declare const transcribeAudio: (fileBuffer: Buffer, mimetype: string, filename?: string) => Promise<string>;
46
+ declare const transcribeAudio: (fileBuffer: Buffer, mimetype: string, filename?: string, contexto?: ContextoTranscripcion | null) => Promise<string>;
53
47
  /**
54
- * Transcribe un WAV que ya viene en el formato que espera Speech-to-Text
55
- * (PCM 16 bits, mono, 16 kHz) y dura menos de 55 segundos. Lo usa el análisis de vídeo,
56
- * que extrae la pista así y ya la recorta.
48
+ * Transcribe un WAV que ya viene en PCM 16 bits, mono, 16 kHz. Lo usa el análisis de vídeo, que
49
+ * extrae la pista así y ya la recorta.
57
50
  *
58
- * @param wavBuffer - Buffer WAV mono 16 kHz de menos de 55 segundos
59
- * @returns Promise<string> - Transcripción del audio
51
+ * @param wavBuffer - Buffer WAV mono 16 kHz
52
+ * @param contexto - Idioma, nombres y últimos mensajes del cliente (opcional)
53
+ * @returns Promise<string> - Transcripción, o un marcador
60
54
  */
61
- declare const transcribeWav16k: (wavBuffer: Buffer) => Promise<string>;
62
- export { transcribeAudio, transcribeWav16k, transcribeWithModel, convertToWav16k, AUDIO_ENCODING_MAP, SYNC_MAX_SECONDS };
55
+ declare const transcribeWav16k: (wavBuffer: Buffer, contexto?: ContextoTranscripcion | null) => Promise<string>;
56
+ export { transcribeAudio, transcribeWav16k, convertToWav16k, MARCADOR_SIN_VOZ, MARCADOR_NO_TRANSCRITO, MARCADOR_ANTIGUO, MARCADORES_AUDIO, TRANSCRIPTION_MAX_SECONDS, MAX_CARACTERES_POR_SEGUNDO, };
57
+ export type { ContextoTranscripcion };
63
58
  //# sourceMappingURL=audio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/audio.ts"],"names":[],"mappings":";AAUA,QAAA,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAa9C,CAAC;AAIF,QAAA,MAAM,gBAAgB,KAAK,CAAC;AAoD5B;;;;;;GAMG;AACH,QAAA,MAAM,mBAAmB,cAAqB,MAAM,KAAG,QAAQ,MAAM,GAAG,IAAI,CA4B3E,CAAC;AAEF;;;;;;GAMG;AACH,QAAA,MAAM,eAAe,eAAgB,MAAM,aAAa,MAAM,KAAG,QAAQ;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAuBtG,CAAC;AAEL;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,eAAe,eAAsB,MAAM,YAAY,MAAM,aAAa,MAAM,KAAG,QAAQ,MAAM,CA4BtG,CAAC;AAEF;;;;;;;GAOG;AACH,QAAA,MAAM,gBAAgB,cAAqB,MAAM,KAAG,QAAQ,MAAM,CAGjE,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/audio.ts"],"names":[],"mappings":";AAKA,OAAO,EAA2C,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAG3G,QAAA,MAAM,yBAAyB,MAAM,CAAC;AAItC,QAAA,MAAM,0BAA0B,KAAK,CAAC;AAKtC,QAAA,MAAM,gBAAgB,gCAAgC,CAAC;AACvD,QAAA,MAAM,sBAAsB,0BAA0B,CAAC;AACvD,QAAA,MAAM,gBAAgB,sCAAsC,CAAC;AAC7D,QAAA,MAAM,gBAAgB,UAA+D,CAAC;AAMtF;;;;;;GAMG;AACH,QAAA,MAAM,eAAe,eAAgB,MAAM,aAAa,MAAM,KAAG,QAAQ;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAuBtG,CAAC;AAoJL;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,eAAe,eAAsB,MAAM,YAAY,MAAM,aAAa,MAAM,aAAa,qBAAqB,GAAG,IAAI,KAAG,QAAQ,MAAM,CAG/I,CAAC;AAEF;;;;;;;GAOG;AACH,QAAA,MAAM,gBAAgB,cAAqB,MAAM,aAAa,qBAAqB,GAAG,IAAI,KAAG,QAAQ,MAAM,CAK1G,CAAC;AAEF,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,0BAA0B,GAC3B,CAAC;AACF,YAAY,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,38 @@
1
+ /// <reference types="node" />
2
+ declare const SPEECH_API_VERSION = "2025-10-15";
3
+ type ResultadoSpeech = {
4
+ text: string;
5
+ confidence: number | null;
6
+ durationMs: number | null;
7
+ };
8
+ /**
9
+ * Traduce el idioma preferido del cliente (`CLIENTE."PREFERRED LANGUAGE"`) al locale de Speech
10
+ *
11
+ * @param lang - Código de idioma ('es', 'en', 'ca'…), o vacío
12
+ * @returns Locale BCP-47; 'es-ES' si no se reconoce
13
+ */
14
+ declare const localeFromPreferredLanguage: (lang?: string | null) => string;
15
+ /**
16
+ * Transcribe un audio con la transcripción rápida de Azure AI Speech.
17
+ *
18
+ * Acepta el archivo tal cual (aac, m4a, mp3, wav, ogg…): Speech detecta el formato por contenido,
19
+ * así que no hace falta convertir a WAV. Sin filtro de palabrotas, porque «joder» forma parte de
20
+ * lo que el cliente dijo y el entrenador tiene que verlo.
21
+ *
22
+ * @param audio - Buffer del audio
23
+ * @param opts - locale del cliente, frases a reforzar (nombres, jerga) y MIME type si se conoce
24
+ * @returns Texto, confianza media de las frases y duración detectada
25
+ * @throws Error si la API responde con error (tras un reintento en 429/5xx)
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const { text } = await transcribeWithAzureSpeech(buffer, { locale: 'es-ES', phrases: ['Rubén', 'fartlek'] });
30
+ * ```
31
+ */
32
+ declare const transcribeWithAzureSpeech: (audio: Buffer, opts: {
33
+ locale: string;
34
+ phrases?: string[];
35
+ mimetype?: string;
36
+ }) => Promise<ResultadoSpeech>;
37
+ export { transcribeWithAzureSpeech, localeFromPreferredLanguage, SPEECH_API_VERSION };
38
+ //# sourceMappingURL=azureSpeech.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azureSpeech.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/azureSpeech.ts"],"names":[],"mappings":";AAKA,QAAA,MAAM,kBAAkB,eAAe,CAAC;AAoBxC,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,2BAA2B,UAAW,MAAM,GAAG,IAAI,KAAG,MAA8E,CAAC;AAoB3I;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,yBAAyB,UAAiB,MAAM,QAAQ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,QAAQ,eAAe,CAoChJ,CAAC;AAEF,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ declare const TRANSCRIBE_API_VERSION = "2025-04-01-preview";
3
+ /**
4
+ * URL y clave del despliegue de transcripción de Azure OpenAI
5
+ *
6
+ * @returns URL completa del endpoint y clave
7
+ * @throws Error si falta AZURE_BASE_URL o AZURE_API_KEY
8
+ */
9
+ declare const getTranscribeConfig: () => {
10
+ url: string;
11
+ key: string;
12
+ deployment: string;
13
+ };
14
+ /**
15
+ * Transcribe un WAV con el despliegue de transcripción de Azure OpenAI, sin prompt.
16
+ *
17
+ * @param wav - Buffer WAV (mono 16 kHz, como sale de `convertToWav16k`)
18
+ * @param opts - Idioma en código de dos letras ('es', 'en'…)
19
+ * @returns Texto transcrito; cadena vacía si el modelo no oyó nada (un "." suelto cuenta como vacío)
20
+ * @throws Error si la API responde con error (tras un reintento en 429/5xx)
21
+ */
22
+ declare const transcribeWithAzureOpenAI: (wav: Buffer, opts: {
23
+ language: string;
24
+ }) => Promise<string>;
25
+ export { transcribeWithAzureOpenAI, getTranscribeConfig, TRANSCRIBE_API_VERSION };
26
+ //# sourceMappingURL=azureTranscribe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azureTranscribe.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/azureTranscribe.ts"],"names":[],"mappings":";AAMA,QAAA,MAAM,sBAAsB,uBAAuB,CAAC;AAMpD;;;;;GAKG;AACH,QAAA,MAAM,mBAAmB;SAAc,MAAM;SAAO,MAAM;gBAAc,MAAM;CAM7E,CAAC;AAEF;;;;;;;GAOG;AACH,QAAA,MAAM,yBAAyB,QAAe,MAAM,QAAQ;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAG,QAAQ,MAAM,CA2BhG,CAAC;AAEF,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC"}
@@ -0,0 +1,64 @@
1
+ declare const GLOSARIO_RUNNING: string[];
2
+ type MensajePrevio = {
3
+ quien: 'cliente' | 'entrenador';
4
+ texto: string;
5
+ };
6
+ type ContextoTranscripcion = {
7
+ /** Solo para el log */
8
+ idMensaje?: number;
9
+ /** CLIENTE."PREFERRED LANGUAGE" */
10
+ idioma?: string | null;
11
+ /** Cliente y entrenadores: refuerzan el reconocimiento y habilitan sus nombres en el filtro */
12
+ nombres?: string[];
13
+ /** Últimos mensajes del chat, del más antiguo al más reciente */
14
+ previos?: MensajePrevio[];
15
+ };
16
+ type Sustitucion = {
17
+ de: string;
18
+ a: string;
19
+ aceptada: boolean;
20
+ };
21
+ /**
22
+ * En qué acabó la capa de corrección. Va en la línea de log de cada audio para poder distinguir
23
+ * «el modelo no vio nada que corregir» de «el modelo no llegó a tiempo»: sin esto, una caída
24
+ * silenciosa del LITE dejaría la corrección apagada de hecho y el log seguiría diciendo 0/0.
25
+ *
26
+ * - `omitida`: texto demasiado corto o TRANSCRIPCION_CORRECCION=off; no se llamó al modelo
27
+ * - `timeout`: el modelo no contestó en CORRECCION_TIMEOUT_MS
28
+ * - `error`: la llamada falló
29
+ * - `sin propuesta`: contestó vacío
30
+ * - `sin cambios`: propuso exactamente el mismo texto
31
+ * - `rechazada`: propuso cambios y el filtro determinista los tumbó todos
32
+ * - `aplicada`: al menos una sustitución pasó el filtro
33
+ */
34
+ type EstadoCorreccion = 'omitida' | 'timeout' | 'error' | 'sin propuesta' | 'sin cambios' | 'rechazada' | 'aplicada';
35
+ /**
36
+ * Normaliza para comparar: minúsculas, sin acentos, solo letras, dígitos y espacios
37
+ *
38
+ * @param texto - Texto de entrada
39
+ * @returns Texto normalizado
40
+ */
41
+ declare const normalizar: (texto: string) => string;
42
+ /**
43
+ * Corrige jerga y nombres de una transcripción con el modelo LITE, dejando pasar solo las
44
+ * sustituciones que el filtro determinista acepta. Nunca lanza: ante cualquier fallo devuelve el
45
+ * texto tal cual.
46
+ *
47
+ * @param texto - Transcripción tal como sale del reconocedor
48
+ * @param contexto - Nombres y últimos mensajes del chat
49
+ * @returns Texto corregido, las sustituciones propuestas con su veredicto y en qué acabó la capa
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * const { texto, estado } = await corregirTranscripcion('Hoy he hecho Farley con el garam', { nombres: ['Ana', 'Rubén'] });
54
+ * // texto: 'Hoy he hecho fartlek con el Garmin', estado: 'aplicada'
55
+ * ```
56
+ */
57
+ declare const corregirTranscripcion: (texto: string, contexto?: ContextoTranscripcion | null) => Promise<{
58
+ texto: string;
59
+ sustituciones: Sustitucion[];
60
+ estado: EstadoCorreccion;
61
+ }>;
62
+ export { corregirTranscripcion, GLOSARIO_RUNNING, normalizar };
63
+ export type { ContextoTranscripcion, EstadoCorreccion, MensajePrevio, Sustitucion };
64
+ //# sourceMappingURL=correccionTranscripcion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correccionTranscripcion.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/correccionTranscripcion.ts"],"names":[],"mappings":"AAWA,QAAA,MAAM,gBAAgB,EAAE,MAAM,EAqD7B,CAAC;AAWF,KAAK,aAAa,GAAG;IAAE,KAAK,EAAE,SAAS,GAAG,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,KAAK,qBAAqB,GAAG;IAC3B,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B,CAAC;AAEF,KAAK,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,KAAK,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,eAAe,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAIrH;;;;;GAKG;AACH,QAAA,MAAM,UAAU,UAAW,MAAM,KAAG,MAOzB,CAAC;AAmKZ;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,qBAAqB,UAClB,MAAM,aACF,qBAAqB,GAAG,IAAI;WACrB,MAAM;mBAAiB,WAAW,EAAE;YAAU,gBAAgB;EAgDjF,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;AAC/D,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC"}
@@ -1,6 +1,9 @@
1
1
  import ffmpeg from 'fluent-ffmpeg';
2
2
  declare const FFMPEG_TIMEOUT_MS = 120000;
3
3
  declare const SPEECH_SAMPLE_RATE = 16000;
4
+ declare const SIN_VOZ_DURACION_MAX_S = 2;
5
+ declare const SIN_VOZ_DB_CLIP_CORTO = -40;
6
+ declare const SIN_VOZ_DB = -60;
4
7
  /**
5
8
  * Ejecuta un comando de ffmpeg como promesa, matándolo si se pasa del tiempo máximo
6
9
  *
@@ -19,6 +22,22 @@ declare const probeMedia: (inputPath: string) => Promise<{
19
22
  hasAudio: boolean;
20
23
  hasVideo: boolean;
21
24
  }>;
25
+ /**
26
+ * Mide el volumen medio de un audio con el filtro `volumedetect` de ffmpeg. Nunca lanza.
27
+ *
28
+ * @param inputPath - Ruta del audio en disco (cualquier formato que ffmpeg decodifique)
29
+ * @returns Volumen medio en dB, o null si no se pudo medir
30
+ */
31
+ declare const measureLoudness: (inputPath: string) => Promise<number | null>;
32
+ /**
33
+ * Decide si un audio no tiene voz que transcribir: muy corto y bajo, o directamente en silencio.
34
+ * Sin medida de volumen nunca se marca: mejor transcribir de más que callar un audio con voz.
35
+ *
36
+ * @param duration - Duración en segundos (0 si no se conoce)
37
+ * @param meanDb - Volumen medio en dB, o null si no se pudo medir
38
+ * @returns true si no merece la pena llamar a ningún motor
39
+ */
40
+ declare const esAudioSinVoz: (duration: number, meanDb: number | null) => boolean;
22
41
  /**
23
42
  * Crea un directorio temporal, ejecuta el trabajo y lo borra pase lo que pase.
24
43
  * En Cloud Run el temporal vive en RAM, así que dejarlo sin borrar cuesta memoria.
@@ -27,5 +46,5 @@ declare const probeMedia: (inputPath: string) => Promise<{
27
46
  * @returns Lo que devuelva `work`
28
47
  */
29
48
  declare const withTempDir: <T>(work: (dir: string) => Promise<T>) => Promise<T>;
30
- export { ffmpeg, runFfmpeg, probeMedia, withTempDir, FFMPEG_TIMEOUT_MS, SPEECH_SAMPLE_RATE };
49
+ export { ffmpeg, runFfmpeg, probeMedia, measureLoudness, esAudioSinVoz, withTempDir, FFMPEG_TIMEOUT_MS, SPEECH_SAMPLE_RATE, SIN_VOZ_DURACION_MAX_S, SIN_VOZ_DB_CLIP_CORTO, SIN_VOZ_DB, };
31
50
  //# sourceMappingURL=ffmpegUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ffmpegUtils.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/ffmpegUtils.ts"],"names":[],"mappings":"AAGA,OAAO,MAAM,MAAM,eAAe,CAAC;AASnC,QAAA,MAAM,iBAAiB,SAAS,CAAC;AAGjC,QAAA,MAAM,kBAAkB,QAAQ,CAAC;AAEjC;;;;;GAKG;AACH,QAAA,MAAM,SAAS,YAAa,GAAG,SAAS,MAAM,KAAG,QAAQ,IAAI,CAqBzD,CAAC;AAEL;;;;;GAKG;AACH,QAAA,MAAM,UAAU,cAAe,MAAM,KAAG,QAAQ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAetG,CAAC;AAEL;;;;;;GAMG;AAEH,QAAA,MAAM,WAAW,kBAAyB,MAAM,8BAW/C,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"ffmpegUtils.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/ffmpegUtils.ts"],"names":[],"mappings":"AAIA,OAAO,MAAM,MAAM,eAAe,CAAC;AASnC,QAAA,MAAM,iBAAiB,SAAS,CAAC;AAGjC,QAAA,MAAM,kBAAkB,QAAQ,CAAC;AAMjC,QAAA,MAAM,sBAAsB,IAAI,CAAC;AACjC,QAAA,MAAM,qBAAqB,MAAM,CAAC;AAClC,QAAA,MAAM,UAAU,MAAM,CAAC;AAEvB;;;;;GAKG;AACH,QAAA,MAAM,SAAS,YAAa,GAAG,SAAS,MAAM,KAAG,QAAQ,IAAI,CAqBzD,CAAC;AAEL;;;;;GAKG;AACH,QAAA,MAAM,UAAU,cAAe,MAAM,KAAG,QAAQ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAetG,CAAC;AAEL;;;;;GAKG;AACH,QAAA,MAAM,eAAe,cAAe,MAAM,KAAG,QAAQ,MAAM,GAAG,IAAI,CAgB9D,CAAC;AAEL;;;;;;;GAOG;AACH,QAAA,MAAM,aAAa,aAAc,MAAM,UAAU,MAAM,GAAG,IAAI,KAAG,OACkE,CAAC;AAEpI;;;;;;GAMG;AAEH,QAAA,MAAM,WAAW,kBAAyB,MAAM,8BAW/C,CAAC;AAEF,OAAO,EACL,MAAM,EACN,SAAS,EACT,UAAU,EACV,eAAe,EACf,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,UAAU,GACX,CAAC"}
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { transcribeAudio } from './audio';
2
+ import { transcribeAudio, ContextoTranscripcion } from './audio';
3
3
  import { describeImage } from './image';
4
4
  import { describeVideo } from './video';
5
5
  import { describePdf, describeTextFile, describeOpaqueFile } from './documents';
@@ -33,6 +33,7 @@ declare const classifyFile: (mimetype: string, filename: string | undefined, fil
33
33
  * @param fileBuffer - Buffer del archivo
34
34
  * @param mimetype - Tipo MIME del archivo
35
35
  * @param filename - Nombre original del archivo
36
+ * @param contexto - Idioma, nombres y últimos mensajes del cliente; solo lo usan audio y vídeo
36
37
  * @returns Promise<string> - Transcripción, descripción, resumen o ficha del archivo
37
38
  *
38
39
  * @example
@@ -41,7 +42,7 @@ declare const classifyFile: (mimetype: string, filename: string | undefined, fil
41
42
  * // "Analítica de sangre del 3 de junio con ferritina de 28 ng/ml..."
42
43
  * ```
43
44
  */
44
- declare const analyzeFile: (fileBuffer: Buffer, mimetype: string, filename?: string) => Promise<string>;
45
+ declare const analyzeFile: (fileBuffer: Buffer, mimetype: string, filename?: string, contexto?: ContextoTranscripcion | null) => Promise<string>;
45
46
  /**
46
47
  * Procesa un adjunto de chat y guarda su texto en la base de datos.
47
48
  * Pensado para llamarse sin await (fire-and-forget) desde el envío del archivo.
@@ -59,22 +60,55 @@ declare const analyzeFile: (fileBuffer: Buffer, mimetype: string, filename?: str
59
60
  * ```
60
61
  */
61
62
  declare const processMediaFile: (idMessage: number, fileBuffer: Buffer, mimetype: string, filename?: string) => Promise<void>;
63
+ type ResultadoReprocesado = {
64
+ id: number;
65
+ antes: string | null;
66
+ despues: string;
67
+ guardado: boolean;
68
+ };
62
69
  /**
63
- * Reprocesa los adjuntos recientes (últimos 2 días) que no tienen FILE TEXT,
64
- * sea cual sea su tipo. Útil para rellenar mensajes anteriores al deploy.
70
+ * Reprocesa los adjuntos recientes (últimos 2 días) que no tienen FILE TEXT o cuya transcripción
71
+ * quedó en un marcador de fallo transitorio, sea cual sea su tipo. Útil tras un deploy o una caída
72
+ * del motor de transcripción. El marcador «sin voz» no se reintenta: es definitivo.
65
73
  *
66
- * @param bucket - Instancia del bucket de Google Cloud Storage
74
+ * @param bucket - Contenedor con `file(ruta).exists()` y `download()`; si no se pasa, el del propio servicio
67
75
  * @returns Promise<{ processed: number; errors: number }> - Estadísticas del reprocesamiento
68
76
  *
69
77
  * @example
70
78
  * ```typescript
71
- * const stats = await reprocessRecentMedia(bucket);
79
+ * const stats = await reprocessRecentMedia();
72
80
  * // Resultado: { processed: 5, errors: 1 }
73
81
  * ```
74
82
  */
75
- declare const reprocessRecentMedia: (bucket: any) => Promise<{
83
+ declare const reprocessRecentMedia: (bucket?: any) => Promise<{
84
+ processed: number;
85
+ errors: number;
86
+ }>;
87
+ /**
88
+ * Reprocesa una lista concreta de adjuntos (p. ej. transcripciones que se sabe que salieron mal)
89
+ * con el pipeline actual. Con `dryRun` calcula el texto nuevo sin guardarlo, para ver antes y
90
+ * después. Sin `dryRun` escribe FILE TEXT: ejecutar a mano y con criterio.
91
+ *
92
+ * @param ids - IDs de CHAT MESSAGE
93
+ * @param opts - `dryRun` para simular; `bucket` para usar otro almacenamiento que el del propio servicio
94
+ * @returns Estadísticas y, por mensaje, texto anterior y nuevo
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * const { resultados } = await reprocessMediaByIds([523437, 501309], { dryRun: true });
99
+ * // resultados[0]: { id: 523437, antes: 'Hola Víctor…', despues: '[Audio sin voz reconocible]', guardado: false }
100
+ * ```
101
+ */
102
+ declare const reprocessMediaByIds: (ids: number[], opts?: {
103
+ bucket?: any;
104
+ dryRun?: boolean;
105
+ }) => Promise<{
76
106
  processed: number;
77
107
  errors: number;
108
+ resultados: ResultadoReprocesado[];
78
109
  }>;
79
- export { transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, describeOpaqueFile, classifyFile, analyzeFile, processMediaFile, reprocessRecentMedia, FILE_KIND, };
110
+ export { transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, describeOpaqueFile, classifyFile, analyzeFile, processMediaFile, reprocessRecentMedia, reprocessMediaByIds, FILE_KIND, };
111
+ export { corregirTranscripcion, GLOSARIO_RUNNING } from './correccionTranscripcion';
112
+ export { MARCADOR_SIN_VOZ, MARCADOR_NO_TRANSCRITO, MARCADORES_AUDIO } from './audio';
113
+ export type { ContextoTranscripcion } from './audio';
80
114
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,EAAuC,MAAM,aAAa,CAAC;AAGrH,QAAA,MAAM,SAAS;;;;;;;CAOL,CAAC;AAEX,KAAK,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAiC3D;;;;;;;;GAQG;AACH,QAAA,MAAM,YAAY,aAAc,MAAM,YAAY,MAAM,GAAG,SAAS,cAAc,MAAM,KAAG,QA0B1F,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,QAAA,MAAM,WAAW,eAAsB,MAAM,YAAY,MAAM,aAAa,MAAM,KAAG,QAAQ,MAAM,CA8BlG,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,gBAAgB,cAAqB,MAAM,cAAc,MAAM,YAAY,MAAM,aAAa,MAAM,KAAG,QAAQ,IAAI,CASxH,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,oBAAoB,WAAkB,GAAG;eAAwB,MAAM;YAAU,MAAM;EAmD5F,CAAC;AAEF,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,SAAS,GACV,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAA4C,MAAM,SAAS,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,EAAuC,MAAM,aAAa,CAAC;AAGrH,QAAA,MAAM,SAAS;;;;;;;CAOL,CAAC;AAEX,KAAK,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAiC3D;;;;;;;;GAQG;AACH,QAAA,MAAM,YAAY,aAAc,MAAM,YAAY,MAAM,GAAG,SAAS,cAAc,MAAM,KAAG,QA0B1F,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,QAAA,MAAM,WAAW,eAAsB,MAAM,YAAY,MAAM,aAAa,MAAM,aAAa,qBAAqB,GAAG,IAAI,KAAG,QAAQ,MAAM,CA8B3I,CAAC;AA2CF;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,gBAAgB,cAAqB,MAAM,cAAc,MAAM,YAAY,MAAM,aAAa,MAAM,KAAG,QAAQ,IAAI,CAaxH,CAAC;AAIF,KAAK,oBAAoB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAwCrG;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,oBAAoB,YAAmB,GAAG;eAAwB,MAAM;YAAU,MAAM;EAmC7F,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,mBAAmB,QAClB,MAAM,EAAE,SACP;IAAE,MAAM,CAAC,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE;eAClB,MAAM;YAAU,MAAM;gBAAc,oBAAoB,EAAE;EAoCjF,CAAC;AAEF,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,SAAS,GACV,CAAC;AACF,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACrF,YAAY,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC"}
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import { ContextoTranscripcion } from './audio';
2
3
  /**
3
4
  * Analiza un vídeo descomponiéndolo en lo que sí sabemos leer: un fotograma
4
5
  * representativo (descrito por el modelo de visión) y su pista de audio
@@ -16,6 +17,6 @@
16
17
  * // "Vídeo de 12 s. Imagen: corredor de perfil sobre cinta... Audio: mira cómo apoyo el talón..."
17
18
  * ```
18
19
  */
19
- declare const describeVideo: (fileBuffer: Buffer, mimetype: string, filename?: string) => Promise<string>;
20
+ declare const describeVideo: (fileBuffer: Buffer, mimetype: string, filename?: string, contexto?: ContextoTranscripcion | null) => Promise<string>;
20
21
  export { describeVideo };
21
22
  //# sourceMappingURL=video.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/video.ts"],"names":[],"mappings":";AAsEA;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,aAAa,eAAsB,MAAM,YAAY,MAAM,aAAa,MAAM,KAAG,QAAQ,MAAM,CAyDpG,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/video.ts"],"names":[],"mappings":";AAIA,OAAO,EAAoB,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAkElE;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,aAAa,eAAsB,MAAM,YAAY,MAAM,aAAa,MAAM,aAAa,qBAAqB,GAAG,IAAI,KAAG,QAAQ,MAAM,CAyD7I,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runnerpro/backend",
3
- "version": "1.34.1",
3
+ "version": "1.35.1",
4
4
  "description": "A collection of common backend functions",
5
5
  "exports": {
6
6
  ".": "./lib/cjs/index.js"
@@ -70,7 +70,6 @@
70
70
  "@ai-sdk/google": "^3.0.43",
71
71
  "@ai-sdk/google-vertex": "^4.0.102",
72
72
  "@azure/storage-blob": "^12.32.0",
73
- "@google-cloud/speech": "^7.2.1",
74
73
  "@google-cloud/storage": "^7.11.3",
75
74
  "@google-cloud/translate": "^8.3.0",
76
75
  "@notionhq/client": "^2.2.15",