Skip to content

ASR and Video Analysis es

Hermes Agent edited this page Oct 1, 2026 · 1 revision

ASR y análisis de vídeo

English | 中文 | 日本語 | 한국어 | Español | Português | Русский

Adjunta un vídeo de Bilibili / YouTube sin subtítulos y browsa obtiene el audio en la propia página, ejecuta ASR en la nube y produce una transcripción [mm:ss] — o ejecuta 视听精读 (lectura profunda audiovisual): un documento de figuras y texto del discurso + lo visual. El proveedor de ASR hoy es Volcengine Ark.

Por qué «descargar → subir archivo» y no pase directo de URL

El pase directo de URL está muerto para AMBAS plataformas: Bilibili firma las URLs del CDN a la IP de sesión del usuario (el servidor de Ark no puede descargarlas); YouTube añade PO-token + sesión + vinculación por cookie (las descargas del lado del servidor reciben 403). El navegador — el cliente cuya IP coincide con la firma — debe obtener los bytes él mismo y subirlos a la Files API. Es una conclusión de causa raíz, no una opción entre varias.

El pipeline (ocho pasos)

  1. ATTACH_PAGE devuelve {mode:'asr-pending'} (traspaso de almacenamiento diferido).
  2. buildAsrPendingCtx despacha por plataforma: Bilibili re-inyecta su content script para leer los streams; YouTube llama al __browsaFetchFreshYouTubeStreams del mundo MAIN (una petición /player fresca que acuña un PO token vigente).
  3. Selección de stream: audio puro de menor bitrate (de todos modos se transcodifica) pero RECHAZAR streams más cortos que el 90% de la duración real (incidente real de stream truncado); preferir AAC-LC (decodeAudioData puede rechazar HE-AAC).
  4. Inyección de cabeceras vía DNR (lib/sidepanel/media-headers.js): Bilibili necesita Referer; YouTube TAMBIÉN necesita reescritura de Origin + cookies (googlevideo da 403 a las descargas de la extensión sin cabeceras — verificado en vivo).
  5. Transcodificar a WAV mono de 16kHz: un m4s de Bilibili es un MP4 fMP4 sin vídeo; Ark clasifica los archivos POR CONTENIDO como «video» → Invalid video_url → estado failed. WAV es el formato probado empíricamente. Decodificación con Web Audio + resample por interpolación lineal escrito a mano (puro, testeable en Node).
  6. Subida a la Files API (multipart de ≤512MB): expire_at = 30 días, nombres de archivo semánticos; browsaArkFileCache almacena los file_ids (clave = base|huella-de-clave|assetId) para que el mismo vídeo se salte la re-subida dentro de 30 días (se sondea su vigencia antes de reutilizar).
  7. Sondeo del estado del archivo → transcripción en streaming vía /responses (input_audio.file_id), con el prompt forzando [mm:ss] por línea.
  8. ATTACH_ASR_CONFIRM almacena la transcripción + el sello videoSrc (la precondición para las píldoras de timestamp / el cajón de línea de tiempo).

Defensas contra el truncado — nunca almacenar en silencio una transcripción parcial (cuatro capas, guiadas por incidentes)

  1. max_output_tokens: 65536 explícito en /responses (el tope de salida por defecto del modelo corta en silencio a mitad del audio).
  2. Parsear las señales SSE incomplete / finish_reason:'length' → truncated:true.
  3. Compuerta de completitud: el último timestamp < 90% de la duración del vídeo → throw, fallo abierto hacia texto plano + toast (NO se almacena).
  4. Compuerta de huecos: largestTranscriptGapSec fusiona por intervalos la línea de tiempo; un hueco > 300s rechaza (un vídeo de 81 minutos perdió una hora en el medio).

Lectura profunda de vídeo (el propio vídeo va al modelo)

input_video (+ input_audio separado opcional), max_output_tokens 65536, salida en streaming de figuras y texto. Disciplina del prompt (calibrada contra ejecuciones reales): etiquetar a los hablantes en cuanto aparezca CUALQUIER segunda voz, añadir nombres identificables, comprimir las lecturas de anuncios a una línea, capturas de keyframe SOLO cuando el argumento dependa de verlas (sugerencia suave de densidad + lista explícita de no-capturar; el único techo duro es el SAFETY_KEYFRAME_CAP 24 del lado del cliente — una guarda contra salidas patológicas, no un control de calidad). Los marcadores [图N] comparten un único protocolo de anclaje con las imágenes de página y el cajón de línea de tiempo.

Notas por plataforma

  • Bilibili: la lista de pistas de /x/player/wbi/v2 + el JSON de subtítulos del CDN se obtienen activamente — independiente del interruptor CC.
  • YouTube: timedtext sirve contenido real SOLO a las peticiones propias del reproductor que llevan POT (las descargas directas de captionTracks.baseUrl devuelven cuerpos vacíos); el interceptor captura material solo si el CC estuvo activo al menos una vez. La etapa de reserva 2c maneja el módulo de subtítulos del reproductor para acuñar una petición autorizada (el breve destello de subtítulos en pantalla es esperado); un veredicto de lista-de-pistas-vacía se cachea negativamente por videoId.
  • «Sin subtítulos» se juzga por la marca estructurada noTranscript, NO por el marcador textual ## 字幕 (el fallback silencioso a Jina del modo auto se traga los marcadores textuales — bug real).

La costura para un segundo proveedor de ASR (reservada)

lib/asr-providers.js (registro de metadatos; cero cambios de UI) + ASR_ADAPTERS en attach-asr.js (misma firma {transcribeAudio, analyzeVideo}). Lo difícil siempre es la capacidad de subida de archivos del endpoint (el audio largo no puede viajar en base64 inline). Un adaptador completo de Qwen/DashScope se construyó y se eliminó tras un día (navegador→OSS inestable; preservado en la historia de git); el fallback de tabCapture de grabar-mientras-se-reproduce fue rechazado (los segmentos en pausa/saltados son silencio — un vídeo no reproducido no puede transcribirse).


Versiones autoritativas: ASR-and-Video-Analysis (inglés) / ASR-and-Video-Analysis-zh (chino) — instantánea de primera traducción por IA, sincronizada el 2026-10-01.

Clone this wiki locally