auto-subtitle — Transcrição automática de áudio/vídeo para SubtitleCue
Um comando para gerar legendas: arquivos de áudio/vídeo de entrada, dois produtos de saída: <nome>.cues.json + <nome>.srt. O contrato de dados está alinhado palavra por palavra com o SubtitleCue do video-motion: {start, end, text}, em segundos com 3 casas decimais, texto em linha única (frases longas já são quebradas em segmentos) — o array subtitles pode ser inserido diretamente na linha do tempo do video-motion.
Etapa 1 · Confirmar material e idioma
- Formatos aceitos: mp4 / wav / flac (decodificação direta com PyAV). Se houver erro de decodificação, converta primeiro:
ffmpeg -i in.mp4 -vn -ac 1 -ar 16000 out.wav - Confirme o idioma e passe
--lang:zh(padrão) /enou códigos de idioma do Whisper. - Material puramente musical ou de efeitos sonoros não precisa ser processado: o VAD filtrará saídas vazias ou muito curtas (isto é uma característica, não um bug).
- Se o material tiver texto conhecido (roteiro falado / falas / texto original), salve-o em UTF-8 — será usado como referência para a verificação L2 na Etapa 3, evitando desvio de referência.
Etapa 2 · Executar transcrição
O venv não é armazenado no repositório (artefato de ~284 MB; .gitignore já cobre .venv/). Por convenção, este skill de modelo não inclui artefatos de build (assim como modelos não incluem node_modules). Portanto, o venv é criado fora do repositório, uma única vez, e reutilizado por todos os projetos:
python -m venv "$env:USERPROFILE\.cache\vibe-studio\asr-venv"
& "$env:USERPROFILE\.cache\vibe-studio\asr-venv\Scripts\python.exe" -m pip install -r skills/auto-subtitle/templates/asr/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
cd skills/auto-subtitle/templates/asr
& "$env:USERPROFILE\.cache\vibe-studio\asr-venv\Scripts\python.exe" transcribe.py <input.mp4|wav> --outdir <diretório de saída>
- Modelo padrão:
large-v3-turbo(~1,6 GB, baixado automaticamente na primeira execução; qualidade satisfatória para chinês). Para validação rápida, adicione--model small(~484 MB). O cache do modelo fica em~/.cache/huggingface, baixado uma vez e reutilizado globalmente. - Se o download do modelo falhar, defina
HF_ENDPOINTpara alterar a fonte: padrão é conexão direta oficial (testada em agosto de 2026). Alternativa:$env:HF_ENDPOINT="https://hf-mirror.com"(nota: pode haver problemas de compatibilidade com redirecionamentos 308 no hub 1.x; prefira a fonte oficial) - Saída padrão (stdout): uma linha de resumo em inglês:
segments=N cues=M total_audio=... model=... lang=... out=.... Exit 0 = sucesso, exit 1 = falha.
Etapa 3 · Verificação em três níveis (obrigatória, não pular)
L1 — Nível de programa: JSON deve ser carregável com json.load; subtitles é um array e cada entrada tem exatamente os três campos start/end/text; start < end e monotonicamente não decrescente entre entradas; valores numéricos com 3 casas decimais; o end da última entrada ≤ duração do ffprobe + 1s. Linhas de timestamp no SRT devem corresponder a HH:MM:SS,mmm --> HH:MM:SS,mmm, numeração contínua a partir de 1.
L2 — Precisão: Se houver texto conhecido → usar difflib.SequenceMatcher para comparação (ambos os lados removem pontuação e espaços em branco, normalizam). Similaridade geral ≥ 0.85, por frase ≥ 0.70 (para frases contínuas, usar janela máxima de concatenação para cobrir divisões/combinações). Se não houver texto conhecido → ouvir amostras do início / meio / fim para verificar.
L2.5 — Eixo temporal (verificação de rotina): As janelas de legenda devem estar alinhadas com as janelas de fala em nível de palavra; não deve haver legendas durante o silêncio entre falas — auditar os intervalos entre entradas adjacentes: deve haver um intervalo de silêncio real >1s entre falas (gap=0 para quebras dentro da mesma frase é normal); não deve haver fragmentos relâmpagos <0,3s; o start da primeira entrada deve estar alinhado com o início da fala; o end da última não deve engolir o silêncio final. O script interno já usa timestamps em nível de palavra (start da primeira palavra / end da última) para definir a janela; esta etapa é a verificação do produto final.
L3 — Linha de conclusão: Tudo ok = ALL GREEN; se houver itens vermelhos → corrigir parâmetros de divisão / VAD e reexecutar; se falhar 2 vezes consecutivas → parar e relatar, proibido ajustes cegos.
Etapa 4 · Entrega
- Relatório: caminho absoluto do
cues.json+ número de cues + duração do áudio + modelo/idioma + conclusão da verificação em três níveis. - Integração com video-motion: o array
subtitlespode ser colado diretamente nosrc/cues.tsdo projeto video-motion, emcues.subtitles, sem conversão de campos. - Explicitamente não faz (para versões futuras): diarização de falantes, exportação de timestamps por palavra, tradução, dublagem TTS.
Etapa 5 · Registrar comando para reexecução
Ao final do relatório de entrega, anexe o comando completo de reexecução (caminho de entrada / --lang / --outdir / --model), garantindo que a próxima sessão ou outra pessoa possa reproduzir exatamente. Os produtos (cues.json / srt) devem ser salvos na área de produtos (neste repositório: products/; em repositórios cruzados: raiz output/) e não entram no git. O comando é o ativo.
Limites e armadilhas
- Console GBK: o script imprime tudo em inglês; ao escrever arquivos, usar explicitamente
encoding="utf-8", JSON comensure_ascii=False. - Regra de divisão: frases com >20 caracteres são quebradas em pontuação (。!?;,、). Se não houver pontuação dentro da janela, quebra forçada com pelo menos 3 caracteres no último fragmento (evitar fragmentos de 1 caractere). Fragmentos <0,3s são fundidos com a entrada anterior, sem exceder o limite de 20 caracteres.
- Timestamps em nível de palavra são a única fonte correta para a janela de legenda — timestamps em nível de segmento engolem o silêncio entre falas, fazendo com que as legendas apareçam aproximadamente um segmento de silêncio antes (já corrigido, não reverter para
word_timestamps=False). - Inferência CPU int8: áudio de 28s ≈ resultado em menos de 1 minuto; para áudio longo, estimar proporcionalmente.
large-v3-turbona primeira execução inclui download, ajustar timeout adequadamente. - No reconhecimento de chinês, números geralmente são convertidos para algarismos arábicos ("duzentos milissegundos" → "200 milissegundos"). Diferença normal na comparação L2, não considerada erro de reconhecimento.
Conexão de entrega
O SRT/cues final deve ser arquivado junto com a fonte de áudio original e a versão do modelo. Não enviar apenas o mp4 com legendas embutidas. Ao entregar o vídeo, usar media-qc para verificar as janelas de legenda com a duração real; a precisão deve ser verificada novamente com o roteiro conhecido ou por amostragem auditiva. O download padrão do modelo e a inferência local não substituem a dublagem humana.