Auto Demo Producer(自動デモプロデューサー)
任意のWebアプリケーションのプロフェッショナルなナレーション付きビデオデモを自動生成します。
パイプライン概要
ユーザーコンテキスト → デモスクリプト → スライド → TTSナレーション → ブラウザ録画 → 最終MP4
3つのフェーズで完全自動化:
- ナレーション — edge-tts(無料のMicrosoft Neural TTS)がシーンごとに音声を生成
- 録画 — PlaywrightがヘッドレスChromiumを駆動し動画をキャプチャ
- 合成 — ffmpegが動画と音声を結合し洗練されたMP4に
起動タイミング
- ユーザーが「デモを作成して」「ウォークスルーを録画して」「ビデオデモを作って」と依頼したとき
- ユーザーがURLと表示内容の説明を提供したとき
- ユーザーがナレーション付きの自動スクリーンキャストを希望したとき
ステップバイステップのワークフロー
ステップ1:コンテキストの収集
ユーザーに以下を尋ねます:
- ターゲットURL — デモ対象のWebアプリケーション(例:
https://myapp.azurewebsites.net) - 表示内容 — 主要機能、ユーザーフロー、シナリオ
- 視聴者 — 誰が視聴するか?(役員、開発者、顧客)
- 目標時間 — デモの長さ(通常1~5分)
- 音声設定 — 言語と性別(デフォルト:
en-US-JennyNeural) - ブランディング — 製品名、サブタイトル、組織、イントロ/アウトロのアクセントカラー
ステップ2:デモスクリプトの作成
以下の形式で demo_script.md を生成します:
# デモ:{製品名}
## intro | 5
> slide intro
製品名のデモへようこそ。本日は主要機能をご紹介します。
## login | 8
> goto {base_url}
> fill Username [email protected]
> fill Password ****
> click button Sign In
ここでデモ用の認証情報を使ってアプリケーションにサインインします。
## dashboard | 10
> wait 2
> scroll down 300
ダッシュボードには、すべてのアクティブなアイテムのリアルタイム概要が表示されます。
## feature_one | 12
> click link Feature One
> wait 1
> scroll down 200
ワークフローを作成・管理できる機能1を見てみましょう。
## outro | 5
> slide outro
ご視聴ありがとうございました!詳細はcontoso.comをご覧ください。
スクリプト形式のルール:
## シーンID | 最小秒数— シーンヘッダー> アクション 引数...— Playwrightアクション(後述のアクションリファレンス参照)- プレーンテキスト行 = ナレーション(TTS音声で読み上げ)
- ナレーションが実際のシーン時間を決定(音声長に合わせて調整)
ステップ3:スライドの生成
スライドジェネレーターを実行してイントロ/アウトロのHTMLファイルを作成:
python generate_slides.py `
--title "製品名" `
--subtitle "ここにタグライン" `
--org "Contoso" `
--badge "Powered by Azure" `
--accent "#60a5fa" `
--out-dir ./slides
ステップ4:依存関係のインストール
pip install edge-tts playwright
playwright install chromium
# ffmpegが利用可能であることを確認:
# Windows: winget install Gyan.FFmpeg
# macOS: brew install ffmpeg
# Linux: sudo apt install ffmpeg
ステップ5:レコーダーの実行
python record_demo.py `
--script demo_script.md `
--base-url "https://myapp.azurewebsites.net" `
--voice en-US-JennyNeural `
--slides-dir ./slides `
--output demo_final.mp4
追加オプション:
--resolution 1280x720でファイルサイズを小さく--var project_id=abc123でスクリプト内のカスタム変数--var [email protected]でパラメータ化されたフロー
ステップ6:レビューと反復
録画後、出力動画を確認します。よくある調整:
- 速すぎる? シーンヘッダーの
min_durationを増やす - タイミングがずれている? ステップ間に
> wait Nアクションを追加 - ステップが足りない? スクリプトにシーンを追加
- 声が合わない? 別のedge-tts音声を試す
アクションリファレンス
| アクション | 構文 | 説明 |
|---|---|---|
goto | > goto https://url.com | URLに移動 |
slide | > slide intro | スライドディレクトリからHTMLスライドを表示 |
click | > click link リンクテキスト | テキストでリンクをクリック |
click | > click button ボタンテキスト | テキストでボタンをクリック |
click | > click text 任意のテキスト | テキストで任意の要素をクリック |
fill | > fill ラベル 値 | フォームテキストボックスに入力 |
type | > type #セレクタ 値 | CSSセレクタで要素にタイプ入力 |
hover | > hover 要素テキスト | 要素にホバー |
select | > select ラベル オプション | ドロップダウンオプションを選択 |
scroll | > scroll down 300 | 下にピクセル数分スクロール |
scroll | > scroll up 200 | 上にピクセル数分スクロール |
wait | > wait 2 | N秒間一時停止 |
screenshot | > screenshot name.png | スクリーンショットを保存 |
音声選択
人気のedge-tts音声(すべて無料、APIキー不要):
| 音声 | 言語 | スタイル |
|---|---|---|
en-US-JennyNeural | 英語(米国) | 温かみのある会話調 |
en-US-GuyNeural | 英語(米国) | プロフェッショナルで明瞭 |
en-US-AriaNeural | 英語(米国) | 自然で汎用性が高い |
en-GB-SoniaNeural | 英語(英国) | 洗練されたプロフェッショナル |
it-IT-IsabellaNeural | イタリア語 | 自然で明瞭 |
de-DE-KatjaNeural | ドイツ語 | プロフェッショナル |
fr-FR-DeniseNeural | フランス語 | エレガント |
es-ES-ElviraNeural | スペイン語 | 明瞭 |
ja-JP-NanamiNeural | 日本語 | 自然 |
zh-CN-XiaoxiaoNeural | 中国語 | 汎用性が高い |
全リスト:edge-tts --list-voices
変数
スクリプト内で {変数名} を使用します。組み込み変数:
{base_url}—--base-url引数で設定
--var key=value によるカスタム変数:
> goto {base_url}/projects/{project_id}
> fill Search {search_term}
出力
このスキルが生成するもの:
demo_final.mp4— H.264ビデオ、AACオーディオ、Web最適化(faststart)- 解像度:1920×1080(デフォルト)またはカスタム
- 品質:CRF 18(高品質)、AAC 192kbps
優れたデモを作るためのヒント
- まずスクリプト — アクションの前にナレーションを書く。ストーリーがペースを決める。
- 短いシーン — 1シーン8~15秒。簡潔に。
- 余裕を持った待機 — ナビゲーション後に
> wait 1-2を追加し、視覚的な余裕を持たせる。 - ナレーションとアクションを一致させる — 画面上で起こっていることを説明する。
- イントロ/アウトロスライド — 常に使用してプロフェッショナルな仕上がりに。
- 段階的にテスト — まず1シーン録画してタイミングを確認し、徐々に追加する。
- ブランドの一貫性 — イントロ/アウトロスライドの色は、PoCのブランドパレット(
threadlight-designクロスカッティングパターン1から)と完全に一致させる必要があります。赤をブランドカラーとする顧客にデフォルトの青/紫グラデーションを使わないでください。PoCのdemo-deck.htmlからCSSカスタムプロパティをコピーしてスライドHTMLファイルに貼り付けてください。 - 字幕 — ナレーションテキストからWebVTTファイルを生成します。外部
<track src="file.vtt">は使用しないでください — Edgeはfile://プロトコルでのCORSをブロックします。代わりに、VTTをインラインでJS Blob URLとして埋め込んでください:var blob = new Blob([vttData], {type:'text/vtt'}); track.src = URL.createObjectURL(blob);そして動的に<track>要素を追加します。タイムスタンプはHH:MM:SS.mmm形式を使用する必要があります(MM:SS.mmではありません — Edgeはそれを拒否します)。 - デッキに埋め込む — PoCが
demo-deck.htmlを出荷する場合、ライブデモホールディングカードのフォールバックとして動画を埋め込みます。Vキートグルを配線します:Vを押すと.is-cueスライド上で動画がインライン再生され、もう一度Vを押すと停止します。プレゼンターがキーボードショートカットだけに依存しないよう、可視のコントロールバー(再生/一時停止ボタン+クリック可能なプログレスバー+時間表示)を追加します。endedイベントで自動停止します。フォールバックヒント(「Vキーで録画フォールバックを再生」)は、キューテキストの下に低い不透明度で表示されます。
エージェントデモの録画(実戦で試されたパターン)
このセクションは、FoundryホステッドエージェントPoCでの6回の失敗した録画試行から抽出されました。 以下のパターンは、エージェントの応答時間が予測不可能(10~50秒)な場合に、確実に視聴可能な動画を生成する唯一のアプローチです。
問題
AIエージェントのデモは リアルタイムでは録画できません。エージェントの応答に10~50秒かかります。ブラウザを継続的に録画し、事前生成したナレーション音声を重ねると、画面がまだ「Working...」を表示している間に音声が答えを説明してしまいます。事後の速度変更やオーディオシフトでは、これを確実に修正できません — 2つのタイムラインが根本的に非同期になるからです。
解決策:シーンごとのスクリーンショットベースジャンプカット
動画内に「Working...」を決して表示しないでください。「質問を入力」から「回答がレンダリングされた」状態へ直接ジャンプカットします。エージェントの待機時間は カメラの外(スクリーンショット間)で発生します。
シーンごとのワークフロー:
- プロンプトを入力 → 入力状態のスクリーンショットを撮る(ナレーターがこのフレーム上で質問を紹介)
- 「Ask」をクリック → 応答が完全にレンダリングされるまでポーリング(カメラの外 — 録画なし)
- 完了した回答のスクリーンショットを撮る(ナレーターがこのフレーム上で応答を説明)
- セグメントを構築:静止画像+対応するナレーション音声クリップ(正確に時間を一致させる)
- すべてのセグメントを連結:イントロ → K1入力 → K1完了 → K2入力 → K2完了 → … → アウトロ
スマート待機 — 出現→消滅ポーリング:
# フェーズ1:ローディングインジケータがAPPEARするのを待つ(API呼び出し開始を確認)
for _ in range(30):
if await page.evaluate("() => !!document.body.innerText.match(/Working/)"):
break
await page.wait_for_timeout(500)
# フェーズ2:ローディングインジケータがDISAPPEARするのを待つ(応答レンダリングを確認)
for _ in range(120):
if not await page.evaluate("() => !!document.body.innerText.match(/Working/)"):
break
await page.wait_for_timeout(1000)
await page.wait_for_timeout(2000) # DOMの安定化
正規表現(/Working/)を、ワークスペースで使用されているローディングインジケータに合わせて調整してください。2フェーズパターンは、「Working...」が表示される前にスクリプトがチェックしてすぐに進んでしまう一般的なバグを防ぎます。
静止画像+音声からのセグメント構築:
def make_segment(image_path, audio_path, output_path):
audio_dur = ffprobe_duration(audio_path)
subprocess.run([
"ffmpeg", "-y",
"-loop", "1", "-i", str(image_path),
"-i", str(audio_path),
"-c:v", "libx264", "-preset", "fast", "-crf", "18",
"-c:a", "aac", "-b:a", "192k",
"-t", str(audio_dur),
"-pix_fmt", "yuv420p",
"-movflags", "+faststart", str(output_path),
], check=True)
各セグメントの長さは、そのナレーション音声と等しくなります — ナレーターは常に画面上の内容を説明します。
アンチパターン(FoundryホステッドエージェントPoCでの6回の失敗した録画試行から)
| ❌ アプローチ | 失敗する理由 |
|---|---|
| 連続録画+後から音声を重ねる | 音声と動画のタイムラインが決して一致しない — ナレーターが引用について話している間、画面は「Working...」を表示 |
setpts で「Working...」部分を高速化 | 見た目がぎこちない;速度変更係数が予測不可能なエージェント応答時間に依存 |
スクリプト内の固定 > wait 35 タイマー | エージェント応答時間は10~50秒;固定タイマーは回答を途中で切るか、何も表示されない30秒を無駄にする |
| 動画と音声をリアルタイムで同時録画 | Playwrightはシステム音声をキャプチャできない;ヘッドレスChromiumにオーディオデバイスがない |
| 音声シフト検出で後処理 | 脆弱すぎる;「Working...」テキストはDOMに現れるが、視覚的なローディングスピナーはワークスペースごとに異なる |
エージェントデモの音声選択
英国の視聴者向けPoCでは 英国英語の音声(en-GB-SoniaNeural)を使用してください — デモのペースで自然に読み上げられ、プロフェッショナルな印象に合います。規制産業向けデモ(FSI、通信、ヘルスケア)では、米国英語のカジュアルな音声は避けてください。
ファイルの場所
グローバルCopilot CLIスキルとして有効化した場合、スクリプトは以下にあります:
~/.copilot/skills/auto-demo-producer/scripts/record_demo.py~/.copilot/skills/auto-demo-producer/scripts/generate_slides.py
実行前にプロジェクトディレクトリにコピーするか、直接参照してください。
前提条件
- Python 3.10+ と
pip - edge-tts —
pip install edge-tts(無料のMicrosoft Neural TTS) - Playwright —
pip install playwright && playwright install chromium - ffmpeg — システムバイナリ(インストールコマンドは上記参照)