Demo Voiceover Skill
Genera y sincroniza narraciones de voz AI para videos de demostración.
Cómo Encaja
Este es el tercer paso del pipeline de videos de demostración:
/demo-script → /record-demo → /demo-voiceover
(planificar) (capturar) (narrar y entregar)
También se puede usar de forma independiente para añadir narración a cualquier video existente con su registro de marcas de tiempo.
Entradas
La habilidad necesita:
- JSON del guión de demostración — de
/demo-script(workspace/<fecha>/demo-script-<nombre>.json) - Archivo de video raw — de
/record-demo(workspace/<fecha>/<nombre>_raw.mp4) - Registro de marcas de tiempo — de
/record-demo(workspace/<fecha>/<nombre>_timestamps.json)
Formato del registro de marcas de tiempo (producido por /record-demo):
{
"video_file": "demo_raw.mp4",
"start_epoch": 1739545200.0,
"steps": [
{
"scene_id": "intro",
"step_index": 0,
"action": "navigate",
"narration": "Bienvenido a OneTest. Vamos a crear tu primer caso de prueba.",
"timestamp_sec": 0.0,
"completed_sec": 1.2
},
{
"scene_id": "navigate-to-test-cases",
"step_index": 0,
"action": "click",
"narration": "Abre la sección Casos de Prueba desde la barra lateral.",
"timestamp_sec": 3.2,
"completed_sec": 3.8
}
]
}
Pipeline
Etapa 1: Planificación de la Narración
Determina cuándo debe reproducirse cada segmento de narración en relación con el video:
Opciones de estrategia de temporización:
| Estrategia | Cuándo inicia la narración | Mejor para |
|---|---|---|
on_action | En el momento en que comienza la acción (timestamp_sec) | Explicar lo que está por suceder |
after_action | Después de que la acción se completa (completed_sec) | Describir lo que acaba de suceder |
before_action | 0.5s antes de que comience la acción | Generar anticipación |
fill_pause | Durante la ventana de pause_after_ms | Narrar sobre la pausa deliberada |
Por defecto: fill_pause — la narración se reproduce durante la pausa después de cada acción, para que el espectador vea la acción ocurrir y luego escuche la explicación mientras la pantalla está estable. Esto se siente más natural.
Salida de la planificación:
{
"segments": [
{
"index": 0,
"text": "Bienvenido a OneTest. Vamos a crear tu primer caso de prueba.",
"video_start_sec": 1.2,
"max_duration_sec": 2.0
},
{
"index": 1,
"text": "Abre la sección Casos de Prueba desde la barra lateral.",
"video_start_sec": 3.8,
"max_duration_sec": 1.5
}
]
}
Etapa 2: Generación de Audio (ElevenLabs)
Genera cada segmento de narración usando el endpoint con marcas de tiempo de ElevenLabs:
- Retorna alineación a nivel de carácter (duración exacta hasta el milisegundo)
- Permite la generación gratuita de subtítulos
- Soporta encadenamiento de continuidad mediante
previous_request_ids(máx. 3)
Ejecuta python scripts/generate_narration.py --plan voiceover_plan.json --voice rachel --output-dir .
Para detalles de la API, consulta references/elevenlabs-api.md.
Etapa 3: Reconciliación de Temporización
Después de generar el audio, reconcilia las duraciones planificadas vs reales:
- El audio cabe en la ventana disponible -> colocar al inicio planificado
- El audio es más corto -> el silencio adicional está bien (las demos respiran)
- El audio es más largo -> acelerar (máx. 1.15x mediante
atempo), o acortar el texto y regenerar
Limitar el ajuste de velocidad a 1.15x — más allá suena apresurado.
Etapa 4: Ensamblaje de Audio
Fusiona los segmentos de narración con el video usando el script auxiliar:
bash scripts/merge_audio_video.sh demo_raw.mp4 narration_results.json final_demo.mp4
El script construye un filter_complex de ffmpeg con adelay por segmento y atempo para ajustes de velocidad.
Etapa 5: Generación de Subtítulos
Las marcas de tiempo a nivel de carácter de ElevenLabs permiten la generación gratuita de SRT:
- Agrupar caracteres en palabras, palabras en líneas de subtítulos (máx. 8 palabras)
- Desplazar por
video_start_secde cada segmento - Salida en formato SRT estándar
Para incrustar subtítulos en el video:
ffmpeg -i final_demo.mp4 -vf subtitles=demo.srt \
-c:v libx264 -crf 18 -c:a copy \
final_demo_subtitled.mp4
Configuración de Voz
Elige la voz según la audiencia, usa eleven_turbo_v2 para borradores, eleven_multilingual_v2 para la versión final.
Para IDs de voz, guía de configuración, comparación de modelos y detalles de encadenamiento de continuidad, consulta references/elevenlabs-api.md.
Ajustes de Ritmo
| Problema | Solución | Límite |
|---|---|---|
| Audio ligeramente demasiado largo | Acelerar con filtro atempo | Máx. 1.15x |
| Audio bastante demasiado largo | Acortar el texto de narración, regenerar | Regenerar solo el segmento |
| Audio demasiado corto | Añadir relleno de silencio (natural) | El silencio durante las demos está bien |
| Espacio incómodo entre segmentos | Extender pausa o añadir frase de transición | Mantener pausas bajo 3s |
Archivos de Salida
| Archivo | Descripción |
|---|---|
<nombre>_final.mp4 | Video + narración fusionados |
<nombre>_final_subtitled.mp4 | Video + narración + subtítulos incrustados |
<nombre>.srt | Archivo de subtítulos (separado) |
<nombre>_narration_full.mp3 | Pista de audio completa de narración (para reutilizar) |
narration_NNN.mp3 | Segmentos individuales (para regeneración) |
<nombre>_voiceover_plan.json | Plan de temporización (para depuración/iteración) |
Todo se guarda en workspace/<fecha>/
Flujo de Trabajo de Iteración
La habilidad permite rehacer segmentos individuales sin regenerar todo:
- El usuario revisa el video: "La narración en la escena 3 es demasiado rápida"
- El agente ajusta: acorta el texto, regenera solo el segmento 3
- Usa
previous_request_idsde los segmentos 1-2 para continuidad - Re-fusiona con ffmpeg (solo cambia la pista de audio, el video se mantiene)
Esto es rápido porque:
- El video no necesita regrabarse
- Solo una llamada API de ElevenLabs por segmento cambiado
- La fusión con ffmpeg toma segundos