Demo Voiceover Skill
Gere e sincronize narração por voz com IA para vídeos de demonstração.
Como se Encaxia
Este é o terceiro estágio do pipeline de vídeos de demonstração:
/demo-script → /record-demo → /demo-voiceover
(planejar) (capturar) (narrar e entregar)
Também pode ser usado de forma independente para adicionar narração a qualquer vídeo existente + registro de timestamps.
Entradas
A skill precisa de:
- JSON do script de demonstração — de
/demo-script(workspace/<data>/demo-script-<nome>.json) - Arquivo de vídeo bruto — de
/record-demo(workspace/<data>/<nome>_raw.mp4) - Registro de timestamps — de
/record-demo(workspace/<data>/<nome>_timestamps.json)
Formato do registro de timestamps (produzido por /record-demo):
{
"video_file": "demo_raw.mp4",
"start_epoch": 1739545200.0,
"steps": [
{
"scene_id": "intro",
"step_index": 0,
"action": "navigate",
"narration": "Bem-vindo ao OneTest. Vamos criar seu primeiro caso de teste.",
"timestamp_sec": 0.0,
"completed_sec": 1.2
},
{
"scene_id": "navigate-to-test-cases",
"step_index": 0,
"action": "click",
"narration": "Abra a seção Casos de Teste pela barra lateral.",
"timestamp_sec": 3.2,
"completed_sec": 3.8
}
]
}
Pipeline
Estágio 1: Planejamento da Narração
Determine quando cada segmento de narração deve tocar em relação ao vídeo:
Opções de estratégia de temporização:
| Estratégia | Quando a narração começa | Melhor para |
|---|---|---|
on_action | No momento em que a ação começa (timestamp_sec) | Explicar o que está prestes a acontecer |
after_action | Após a ação ser concluída (completed_sec) | Descrever o que acabou de acontecer |
before_action | 0,5s antes da ação começar | Criar expectativa |
fill_pause | Durante a janela de pause_after_ms | Narrar durante a pausa deliberada |
Padrão: fill_pause — a narração toca durante a pausa após cada ação, para que o espectador veja a ação acontecer e depois ouça a explicação enquanto a tela está estável. Isso parece o mais natural.
Saída do planejamento:
{
"segments": [
{
"index": 0,
"text": "Bem-vindo ao OneTest. Vamos criar seu primeiro caso de teste.",
"video_start_sec": 1.2,
"max_duration_sec": 2.0
},
{
"index": 1,
"text": "Abra a seção Casos de Teste pela barra lateral.",
"video_start_sec": 3.8,
"max_duration_sec": 1.5
}
]
}
Estágio 2: Geração de Áudio (ElevenLabs)
Gere cada segmento de narração usando o endpoint with-timestamps da ElevenLabs:
- Retorna alinhamento em nível de caractere (duração exata em milissegundos)
- Permite geração gratuita de legendas
- Suporta encadeamento de continuidade via
previous_request_ids(máx. 3)
Execute python scripts/generate_narration.py --plan voiceover_plan.json --voice rachel --output-dir .
Para detalhes da API, consulte references/elevenlabs-api.md.
Estágio 3: Reconciliação de Temporização
Após gerar o áudio, reconcilie as durações planejadas com as reais:
- Áudio cabe na janela disponível -> colocar no início planejado
- Áudio mais curto -> silêncio extra é aceitável (demos respiram)
- Áudio mais longo -> acelerar (máx. 1,15x via
atempo), ou encurtar o texto e regerar
Limite o ajuste de velocidade em 1,15x — além disso soa apressado.
Estágio 4: Montagem do Áudio
Mescle segmentos de narração com o vídeo usando o script auxiliar:
bash scripts/merge_audio_video.sh demo_raw.mp4 narration_results.json final_demo.mp4
O script cria um filter_complex do ffmpeg com adelay por segmento e atempo para ajustes de velocidade.
Estágio 5: Geração de Legendas
Os timestamps em nível de caractere da ElevenLabs permitem geração gratuita de SRT:
- Agrupe caracteres em palavras, palavras em linhas de legenda (máx. 8 palavras)
- Desloque pelo
video_start_secde cada segmento - Gere no formato SRT padrão
Para incorporar legendas ao vídeo:
ffmpeg -i final_demo.mp4 -vf subtitles=demo.srt \
-c:v libx264 -crf 18 -c:a copy \
final_demo_subtitled.mp4
Configuração de Voz
Escolha a voz com base no público; use eleven_turbo_v2 para rascunhos e eleven_multilingual_v2 para final.
Para IDs de voz, guia de configurações, comparação de modelos e detalhes de encadeamento de continuidade, consulte references/elevenlabs-api.md.
Ajustes de Ritmo
| Problema | Solução | Limite |
|---|---|---|
| Áudio ligeiramente longo | Acelerar com filtro atempo | Máx. 1,15x |
| Áudio muito longo | Encurtar texto da narração, regerar | Regenerar apenas o segmento |
| Áudio muito curto | Adicionar silêncio (natural) | Silêncio durante demos é aceitável |
| Pausa estranha entre segmentos | Aumentar pausa ou adicionar frase de transição | Manter pausas abaixo de 3s |
Arquivos de Saída
| Arquivo | Descrição |
|---|---|
<nome>_final.mp4 | Vídeo + narração mesclados |
<nome>_final_subtitled.mp4 | Vídeo + narração + legendas incorporadas |
<nome>.srt | Arquivo de legenda (separado) |
<nome>_narration_full.mp3 | Faixa de áudio da narração completa (para reutilização) |
narration_NNN.mp3 | Segmentos individuais (para regeneração) |
<nome>_voiceover_plan.json | Plano de temporização (para depuração/iteração) |
Todos salvos em workspace/<data>/
Fluxo de Iteração
A skill suporta refazer segmentos individuais sem regenerar tudo:
- Usuário revisa o vídeo: "A narração na cena 3 está muito rápida"
- Agente ajusta: encurta o texto, regera apenas o segmento 3
- Use
previous_request_idsdos segmentos 1-2 para continuidade - Remescle com ffmpeg (apenas a faixa de áudio muda, o vídeo permanece)
Isso é rápido porque:
- O vídeo não precisa ser regravado
- Apenas uma chamada de API da ElevenLabs por segmento alterado
- A mesclagem com ffmpeg leva segundos