デモ音声ナレーションスキル は何をしますか?
デモ動画用のAI音声ナレーションを生成し、動画と同期します。
位置づけ
デモ動画パイプラインの第3段階です:
/demo-script → /record-demo → /demo-voiceover
(計画) (画面収録) (ナレーション & 納品)
また、既存の動画とタイムスタンプログにナレーションを追加するスタンドアロン用途としても使用できます。
入力
スキルに必要なもの:
- デモスクリプトJSON —
/demo-scriptから(workspace/<date>/demo-script-<name>.json) - 生動画ファイル —
/record-demoから(workspace/<date>/<name>_raw.mp4) - タイムスタンプログ —
/record-demoから(workspace/<date>/<name>_timestamps.json)
タイムスタンプログの形式(/record-demo が出力):
{
"video_file": "demo_raw.mp4",
"start_epoch": 1739545200.0,
"steps": [
{
"scene_id": "intro",
"step_index": 0,
"action": "navigate",
"narration": "OneTestへようこそ。最初のテストケースを作成しましょう。",
"timestamp_sec": 0.0,
"completed_sec": 1.2
},
{
"scene_id": "navigate-to-test-cases",
"step_index": 0,
"action": "click",
"narration": "サイドバーからテストケースセクションを開きます。",
"timestamp_sec": 3.2,
"completed_sec": 3.8
}
]
}
パイプライン
ステージ1:ナレーション計画
各ナレーションセグメントを動画に対してどのタイミングで再生するかを決定します:
タイミング戦略のオプション:
| 戦略 | ナレーション開始タイミング | 最適な用途 |
|---|---|---|
on_action | アクション開始時点(timestamp_sec) | これから起こることの説明 |
after_action | アクション完了後(completed_sec) | 起こったことの説明 |
before_action | アクション開始0.5秒前 | 期待感の醸成 |
fill_pause | pause_after_ms のウィンドウ中 | 意図的な一時停止中のナレーション |
デフォルト:fill_pause — 各アクション後の一時停止中にナレーションを再生します。視聴者はアクションが発生するのを見てから、画面が安定している間に説明を聞くことができます。これが最も自然な感覚です。
計画出力:
{
"segments": [
{
"index": 0,
"text": "OneTestへようこそ。最初のテストケースを作成しましょう。",
"video_start_sec": 1.2,
"max_duration_sec": 2.0
},
{
"index": 1,
"text": "サイドバーからテストケースセクションを開きます。",
"video_start_sec": 3.8,
"max_duration_sec": 1.5
}
]
}
ステージ2:音声生成(ElevenLabs)
ElevenLabsのタイムスタンプ付きエンドポイントを使用して各ナレーションセグメントを生成します:
- 文字レベルのアライメント(ミリ秒単位の正確な長さ)を返す
- 字幕生成が無料で可能
previous_request_idsによる継続性チェーンをサポート(最大3つ)
実行コマンド:python scripts/generate_narration.py --plan voiceover_plan.json --voice rachel --output-dir .
APIの詳細については、references/elevenlabs-api.md を参照してください。
ステージ3:タイミング調整
音声生成後、計画された長さと実際の長さを調整します:
- 音声が収まる → 計画された開始位置に配置
- 音声が短い → 追加の無音は問題なし(デモでは息継ぎとして機能)
- 音声が長い → 速度を上げる(最大1.15倍、
atempoを使用)、またはテキストを短縮して再生成
速度調整は1.15倍が上限 — それを超えると聞き苦しくなります。
ステージ4:音声アセンブリ
ヘルパースクリプトを使用してナレーションセグメントを動画とマージします:
bash scripts/merge_audio_video.sh demo_raw.mp4 narration_results.json final_demo.mp4
このスクリプトは、セグメントごとに adelay と速度調整用の atempo を使用した ffmpeg の filter_complex を構築します。
ステージ5:字幕生成
ElevenLabsからの文字レベルのタイムスタンプにより、無料でSRT字幕を生成できます:
- 文字を単語に、単語を字幕行(最大8単語)にグループ化
- 各セグメントの
video_start_secでオフセット - 標準SRT形式で出力
動画に字幕を焼き付ける場合:
ffmpeg -i final_demo.mp4 -vf subtitles=demo.srt \
-c:v libx264 -crf 18 -c:a copy \
final_demo_subtitled.mp4
音声設定
視聴者に応じて音声を選択します。下書きには eleven_turbo_v2 を、最終版には eleven_multilingual_v2 を使用します。
音声ID、設定ガイド、モデル比較、継続性チェーンの詳細については、references/elevenlabs-api.md を参照してください。
ペーシング調整
| 問題 | 解決策 | 制限 |
|---|---|---|
| 音声が少し長すぎる | atempo フィルタで速度を上げる | 最大1.15倍 |
| 音声が大幅に長すぎる | ナレーションテキストを短縮し再生成 | 該当セグメントのみ再生成 |
| 音声が短すぎる | 無音パディングを追加(自然) | デモ中の無音は問題なし |
| セグメント間の不自然な間隔 | 一時停止を延長するか、トランジション文を追加 | 一時停止は3秒未満に保つ |
出力ファイル
| ファイル | 説明 |
|---|---|
<name>_final.mp4 | 動画 + ナレーション統合 |
<name>_final_subtitled.mp4 | 動画 + ナレーション + 字幕焼き付け |
<name>.srt | 字幕ファイル(別ファイル) |
<name>_narration_full.mp3 | 全ナレーション音声トラック(再利用用) |
narration_NNN.mp3 | 個別セグメント(再生成用) |
<name>_voiceover_plan.json | タイミング計画(デバッグ・反復用) |
すべて workspace/<date>/ に保存されます。
反復ワークフロー
このスキルは、全体を再生成せずに個別のセグメントをやり直すことをサポートします:
- ユーザーが動画を確認:「シーン3のナレーションが速すぎる」
- エージェントが調整:テキストを短縮し、セグメント3のみ再生成
- 継続性のためにセグメント1~2の
previous_request_idsを使用 - ffmpegで再マージ(変更されるのは音声トラックのみ、動画はそのまま)
高速な理由:
- 動画を再録画する必要がない
- 変更されたセグメントごとにElevenLabs API呼び出しが1回のみ
- ffmpegマージは数秒で完了