Criar vídeos dublados com código
Visão Geral
Um vídeo = roteiro finalizado → TTS frase por frase → validação ASR frase por frase → linha do tempo → animação HTML → captura de tela quadro a quadro → montagem com ffmpeg.
Princípio central: a linha do tempo vem do áudio. Primeiro, duble e valide cada frase, meça os tempos reais de início e fim de cada segmento de legenda, e então associe todas as animações visuais a esses tempos. As animações não usam segundos fixos; se a dublagem mudar, basta reexecutar a linha do tempo. A renderização captura quadros da página usando __seek(t), produzindo resultados determinísticos e reproduzíveis.
Adequado para: vídeos explicativos/tutoriais (2–5 minutos), vídeos promocionais de produtos (20–40 segundos), vídeos educacionais com legendas e marcadores de capítulo.
Não adequado para: edição com pessoas reais, vídeos que exigem filmagens reais, MV musicais puros.
Fluxo de Trabalho
Cada etapa tem um ponto de verificação; não prossiga sem que a etapa anterior seja aprovada.
| # | Etapa | Resultado | Ponto de Verificação | Referência |
|---|---|---|---|---|
| 0 | Inicialização | Diretório de trabalho | bash scripts/init.sh <dir> bem-sucedido | Abaixo |
| 1 | Escolha do tópico, verificação, roteiro | script.md, audio/make_script.py | Fatos verificados (experimentos primeiro); o usuário aprova o roteiro antes de começar a dublagem | references/script.md |
| 2 | Dublagem | audio/raw/NN.wav → audio/clips/NN.wav (1.3x) | Cada frase passa pelo ASR; refaça as frases problemáticas | references/voice.md |
| 3 | Linha do tempo | build/narration.wav, build/timeline.json | Segmentação das legendas coincide com a fala | references/timeline.md |
| 4 | Materiais | Capturas de tela reais da interface, saída real do terminal | Consistentes com a narração; use example.com para domínios de exemplo | references/capture.md |
| 5 | Composição | comp/index.html | Verifique cada quadro da composição de imagens lado a lado | references/composition.md |
| 6 | Renderização | dist/video.mp4 | Duração = linha do tempo, loudness -14 LUFS | references/render.md |
| 7 | Capa, texto | dist/cover-bili.png, dist/cover-douyin.png, dist/copy.txt | Capa dentro da área de corte segura de cada plataforma | references/publish.md |
| 8 | Entrega, limpeza | Enviar ao usuário; arquivar arquivos fonte | O usuário confirma que salvou antes de limpar | Abaixo |
Inicialização
bash scripts/init.sh ~/work/<projeto>/video-<episódio> copia template/ para o diretório de trabalho, copia scripts/ para tools/ e instala o playwright-core. O template é uma demonstração de 30 segundos que funciona diretamente. Antes de começar, substitua estes conteúdos de exemplo:
script.md,audio/make_script.py: roteiro do episódio atual; capítulos são definidos apenas uma vez emCHAPTERSnomake_script.py; pausas entre capítulos, barras de capítulo e timestamps de capítulo são derivados dele.audio/direction.txt: o [Cenário] da instrução do diretor de TTS.asr-prompt.txt: glossário de termos do episódio atual (escrita padrão, com pronúncia se necessário).comp/index.html: cenas e animações;comp/cover-*.html: conteúdo da capa.
Comandos Comuns
Execute no diretório de trabalho:
| Comando | Efeito |
|---|---|
python3 audio/make_script.py | Gera audio/script.json e audio/lines.json |
python3 tools/tts.py audio/lines.json audio/raw | Dubla cada frase; reutiliza áudio existente para textos iguais; execute novamente se o roteiro mudar |
bash tools/speed.sh audio/raw audio/clips 1.3 | Altera velocidade sem alterar tom |
python3 tools/asr.py audio/clips --en | Reconhece cada frase: plano / com dicas de termos / modo inglês |
python3 tools/takes.py 3,7 3 | Grava 3 takes das frases 3 e 7 e as pontua |
python3 tools/takes.py audio/var.json 2 | Grava 2 takes de cada variação de uma mesma frase |
python3 tools/tts.py audio/lines.json audio/raw --adopt 3 audio/takes/03-0-1.raw.wav | Adota um take específico |
python3 tools/build_audio.py audio/clips build audio/script.json | Concatena a dublagem e gera a linha do tempo |
python3 tools/align_chunks.py audio/clips build/timeline.json audio/script.json | Alinha os segmentos de legenda com a fala real |
node tools/render.mjs --timeline=build/timeline.json --stills=2,8.5,20 | Captura quadros para build/stills (limpa antes) |
bash tools/contact.sh build/stills build/sheets | Monta composição 2x2; use Read para visualizar |
bash tools/render-par.sh build/timeline.json build/narration.wav dist/video.mp4 8 | Renderiza o vídeo completo com 8 processos paralelos e mixa o áudio |
node tools/render.mjs --html=comp/cover-4x3.html --width=1440 --height=1080 --png=dist/cover-bili.png | Gera capa |
python3 tools/bili_kw.py "nginx configurar certificado ssl" "baota https" | Pesquisa tópico: 6 vídeos mais vistos no B站 por palavra-chave |
Dependências: ffmpeg, Node 18+, Google Chrome nativo, Python 3 + requests + openai-whisper (modelo small). TTS usa MiMo da Xiaomi; a chave é lida da variável de ambiente MIMO_API_KEY ou de um arquivo apontado por MIMO_ENV_FILE; se nenhum for encontrado, pergunte ao usuário. Para usar outro TTS, basta garantir um WAV por frase.
Pontos Mais Propensos a Erro
- Dublar sem aprovação. Envie o roteiro ao usuário primeiro; "continuar/começar/pode" conta como aprovação. Se alterar a redação para melhorar a pronúncia, informe cada alteração ao entregar.
- Legendas e dublagem escritas como uma coisa só. Legendas são para o público ("Nginx", "443", "1.3"), dublagem é para o TTS ler ("Engine X", "quatro quatro três", "um ponto três"). Em
make_script.py, useP(legenda, pronúncia)para separar; a pronúncia concatenada de todos os segmentos deve igualar o texto completo da frase do TTS. - Ouvir apenas a mixagem completa. O reconhecimento da mixagem completa erra termos técnicos em inglês; é necessário reconhecer frase por frase. Para selecionar takes, use apenas a pontuação "plano" e o resultado
--en; a versão "prime" com dicas de termos pode "corrigir" erros de pronúncia incorretamente. Consulte voice.md para as regras de decisão. - Usar segundos fixos nas animações. Após o início da primeira frase, todas as animações devem usar
T(frase, segmento); a duração mudará com a alteração de velocidade ou regravação. - Início da página vazio. Se o conteúdo demorar 2–3 segundos para aparecer após o cartão, parece que travou; o conteúdo deve aparecer já no primeiro segmento de legenda do capítulo.
- Múltiplas animações
fill: bothno mesmo elemento, IDs duplicados. A WAAPI não reporta erro; o elemento pode desaparecer ou parar no estado errado. Consulte composition.md. - Abrir página com
file://para renderização. CSS mask, entre outros, falhará;render.mjsjá fornece um servidor HTTP local. - Capa cortada pela plataforma. No B站, uma imagem é cortada para 4:3 e 16:9; no Douyin, 9:16 é cortada para 3:4; coloque o conteúdo apenas na área segura.
- Redirecionamento violando regras. Não coloque URLs de sites reais, QR codes ou informações de contato na imagem, capa ou texto; não escreva "pode dar uma olhada/pesquisar". Domínios de exemplo como
example.compodem aparecer em interfaces de demonstração e terminais. Vídeos publicados em várias plataformas não devem usar uma plataforma de conteúdo como exemplo; vídeos promocionais não mencionam preços. - Anunciar sucesso antes de ver o resultado. Envie mensagens de progresso somente após o comando terminar e a saída ser exibida.
Entrega e Limpeza
- Entrega: vídeo final, capa 4:3 para B站, capa 9:16 para Douyin,
dist/copy.txt(título, tags, descrição, timestamps de capítulo). O vídeo do B站 é publicado também no Douyin etc., então a capa vertical e o texto do Douyin são gerados juntos; se o usuário especificar uma única plataforma, entregue apenas esse conjunto. Liste todas as alterações de redação feitas para melhorar a pronúncia e peça ao usuário para verificar os pontos de tempo que não está seguro. - Se o arquivo exceder o limite do chat (geralmente 30MB), envie uma versão de visualização com
crf 22e informe a localização da versão em alta definição. Se o envio de arquivos grandes falhar por timeout e for reenviado, lembre o usuário de que pode receber duas cópias. - Após o usuário confirmar que salvou os materiais: arquive os arquivos fonte reutilizáveis (
comp/e materiais usados,audio/make_script.py, especificações de variantes,script.md,copy.txt,direction.txt,asr-prompt.txt, scripts de captura de tela,lab/) no diretório de templates do usuário (se não houver acordo, pergunte onde salvar, por exemplo,~/work/<projeto>/video-template/<episódio>/). Usediff -rpara verificar um a um, e então remova o diretório de trabalho, o perfil do navegador temporário, contêineres, servidores de desenvolvimento (mate por PID, verificando a linha de comando primeiro) e dependências de frontend instaladas apenas para capturas de tela. Mantenha o cache do modelo whisper e imagens Docker.