Skip to content

ASR and Video Analysis pt

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

ASR e análise de vídeo

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

Anexe um vídeo sem legendas do Bilibili / YouTube e o browsa busca o áudio na própria página, roda ASR na nuvem e produz uma transcrição [mm:ss] — ou roda o 视听精读 (leitura profunda audiovisual): um documento de figuras e texto da fala + visuais. O provedor de ASR hoje é o Volcengine Ark.

Por que "baixar → subir o arquivo" e não passagem direta de URL

A passagem direta de URL está morta para AMBAS as plataformas: o Bilibili assina as URLs de CDN para o IP da sessão do usuário (o servidor do Ark não consegue buscá-las); o YouTube adiciona PO-token + sessão + vínculo por cookie (fetches do lado do servidor recebem 403). O navegador — o cliente cujo IP casa com a assinatura — deve buscar os bytes ele mesmo e subi-los para a Files API. Esta é uma conclusão de causa raiz, não uma opção entre várias.

O pipeline (oito passos)

  1. ATTACH_PAGE retorna {mode:'asr-pending'} (handoff de armazenamento diferido).
  2. buildAsrPendingCtx despacha por plataforma: o Bilibili re-injeta seu content script para ler os streams; o YouTube chama o __browsaFetchFreshYouTubeStreams do MAIN world (uma requisição /player fresca cunhando um PO token atual).
  3. Seleção de stream: áudio puro de menor bitrate (será transcodificado de qualquer forma) mas REJEITE streams mais curtos que 90% da duração real (incidente real de stream truncado); prefira AAC-LC (decodeAudioData pode rejeitar HE-AAC).
  4. Injeção de cabeçalhos via DNR (lib/sidepanel/media-headers.js): o Bilibili precisa de Referer; o YouTube TAMBÉM precisa de reescrita de Origin + cookies (o googlevideo devolve 403 a fetches da extensão sem cabeçalhos — verificado ao vivo).
  5. Transcode para WAV mono 16kHz: um m4s do Bilibili é um MP4 fMP4 sem vídeo; o Ark classifica arquivos PELO CONTEÚDO como "vídeo" → Invalid video_url → status failed. WAV é o formato comprovado empiricamente. Decode via Web Audio + ressample por interpolação linear escrito à mão (puro, testável em Node).
  6. Upload para a Files API (multipart de ≤512MB): expire_at = 30 dias, nomes de arquivo semânticos; o browsaArkFileCache guarda file_ids (chave = base|key-fingerprint|assetId) para que o mesmo vídeo pule o re-upload dentro de 30 dias (sondado por liveness antes do reúso).
  7. Polling do status do arquivo → transcrição em streaming via /responses (input_audio.file_id), com o prompt forçando [mm:ss] por linha.
  8. ATTACH_ASR_CONFIRM armazena a transcrição + o carimbo videoSrc (a pré-condição para as pílulas de timestamp / a gaveta de linha do tempo).

Defesas contra truncamento — nunca armazene silenciosamente uma transcrição parcial (quatro camadas, dirigidas por incidentes)

  1. max_output_tokens: 65536 explícito no /responses (o teto de saída padrão do modelo corta silenciosamente no meio do áudio).
  2. Interpretar os sinais SSE incomplete / finish_reason:'length' → truncated:true.
  3. Gate de completude: último timestamp < 90% da duração do vídeo → lança exceção, falha abrindo para texto puro + toast (NÃO armazenado).
  4. Gate de buracos: o largestTranscriptGapSec faz merge por intervalos da linha do tempo; um vão > 300s rejeita (um vídeo de 81 minutos certa vez perdeu uma hora no meio).

Leitura profunda de vídeo (o próprio vídeo vai para o modelo)

input_video (+ input_audio separado opcional), max_output_tokens 65536, saída em streaming de figuras e texto. Disciplina de prompt (calibrada contra execuções reais): rotule os falantes sempre que QUALQUER segunda voz aparecer, acrescente nomes identificáveis, comprima leituras de anúncios a uma linha, screenshots de keyframe SOMENTE quando o argumento depender de vê-los (hint suave de densidade + lista explícita de não-captura; o único teto rígido é o SAFETY_KEYFRAME_CAP 24 do lado do cliente — um guarda contra saída patológica, não um botão de qualidade). Os marcadores [图N] compartilham um protocolo de ancoragem com as imagens da página e a gaveta de linha do tempo.

Notas por plataforma

  • Bilibili: a lista de tracks de /x/player/wbi/v2 + o JSON de legendas da CDN são buscados ativamente — independente do toggle de CC.
  • YouTube: o timedtext serve conteúdo real SOMENTE às requisições do próprio player portadoras de POT (fetches diretos de captionTracks.baseUrl retornam corpos vazios); o interceptor captura material apenas se o CC esteve ligado ao menos uma vez. O estágio de fallback 2c aciona o módulo de legendas do player para cunhar uma requisição autorizada (o breve flash de legenda na tela é esperado); um veredicto de tracklist vazia recebe cache negativo por videoId.
  • "Sem legendas" é julgado pela flag estruturada noTranscript, NÃO pelo marcador de texto ## 字幕 (o fallback Jina silencioso do modo auto engole marcadores de texto — bug real).

A costura para um segundo provedor de ASR (reservada)

lib/asr-providers.js (registro de metadados; zero mudanças de UI) + ASR_ADAPTERS em attach-asr.js (assinatura idêntica {transcribeAudio, analyzeVideo}). A parte difícil é sempre a capacidade de upload de arquivo do endpoint (áudio longo não pode ir em base64 inline). Um adaptador completo Qwen/DashScope foi construído e removido após um dia (browser→OSS instável; preservado no histórico do git); o fallback tabCapture de gravar-enquanto-reproduz foi rejeitado (segmentos pausados/pulados são silêncio — um vídeo não reproduzido não pode ser transcrito).


Versões autoritativas: ASR-and-Video-Analysis (inglês) / ASR-and-Video-Analysis-zh (chinês) — instantâneo de primeira tradução por IA, sincronizado em 2026-10-01.

Clone this wiki locally