• #日記
  • #ElevenLabs
  • #TTS
  • #Cloudflare R2
  • #NarrationViewer
  • #eurekapu
daily-log

2026年3月16日の開発日記

前日にVOICEVOXとGoogle Cloud TTSでナレーション機能を組み上げたのを受けて、今日は音声の品質・管理・配信の3つを一気に底上げした。朝にElevenLabs v3のAPIを叩き始め、夜にはステレオパン付きのナレーションが本番環境から流れるところまで持っていった。

今日やったこと

1. ElevenLabs v3 TTS導入と音声サービス比較

日本語TTSを4サービス(OpenAI TTS、Google Cloud TTS、ElevenLabs v3、VOICEVOX)で比較した。ElevenLabs v3が最も自然な日本語を生成すると判断し、APIスクリプトを組んでテスト音声を生成。Audio Tagsで文中に[gentle][serious]を挿入して感情を揺らすテストも実施した。聞き比べページ(/admin/voice-compare)を立てて3サービスを横並びで再生できるようにし、最終的にChapter 04全59行をElevenLabsで本番生成した。

主な成果:

  • 4サービスの比較調査とElevenLabs v3の選定
  • Audio Tags感情制御(文中挿入パターン)のテスト
  • 聞き比べページ(4カラム構成)の構築
  • Chapter 04の全59行をElevenLabsで本番生成(3,458文字消費)

詳細: ElevenLabs v3で日本語TTS - サービス比較から本番生成まで


2. 音声ファイル管理基盤の整備

152個の音声ファイルをpublic/audio/からaudio-assets/に移行し、.gitignoreで除外した。dev server middleware(dev-audio.ts)を作成してローカル開発でaudio-assets/から配信し、useAudioUrl composableで本番(R2 CDN)と開発(ローカル)のURL解決を一元化した。Cloudflare R2にElevenLabs音声とVOICEVOX音声をアップロードし、DEPLOY.mdにデプロイ手順を文書化した。

主な成果:

  • audio-assets/ への一元移行(gitignore済み)
  • dev middleware + useAudioUrl composable でURL解決統一
  • R2アップロード(--remoteフラグ忘れの教訓も記録)
  • DEPLOY.md 作成

詳細: 音声ファイル管理基盤の整備 - Git除外・R2配信・dev middleware構築


3. ナレーションコンテンツ改善とNarrationViewer拡張

Chapter 01+04の計196行のナレーションを通しレビューし、未解説の専門用語やスライドのずれ、scene.idの重複など8件の問題を修正した。旧プロジェクトから移行時に書き換わっていたメッセージラインを原文に忠実に復元。NarrationViewerにはmessageLine表示、ステレオパン(ユイ=左、カイ先生=右)、デバッグパネル(Dキー)を追加した。Playwright+ffmpegによる動画レンダリングも試行し、NarrationViewerのロジックを純粋関数に抽出してVitest 49テストを新規作成した。

主な成果:

  • 196行の通しレビューで8件修正
  • messageLine原文復元(旧プロジェクトとの整合性)
  • ステレオパン実装とデバッグパネル追加
  • Playwright+ffmpegで動画レンダリングのパイプライン構築
  • 純粋関数抽出 + 49テスト新規作成(全292テスト合格)
  • 命名規則移行計画(Section > Chapter > Topic)のマークダウン作成

詳細: ナレーションコンテンツ改善とNarrationViewer拡張


今日の試行錯誤

#テーマ試したこと結果気づき
1ElevenLabs API権限TTS権限のみでキー発行音声生成OK、使用量確認NG最小権限で始めるのは正解だが段階的追加が必要
2user_read権限を追加使用量OK、ボイス検索NG権限は機能単位で分かれている
3voices_readを追加(保存ボタン押し忘れ)反映されずUIの保存ボタン見落とし注意
4保存を確認して再実行全権限通った計4回で全機能アクセス可能に
5R2アップロードwrangler r2 object putで59ファイルCDNで全404デフォルトはローカルエミュレータに書き込む
6--remoteフラグ付きで再アップロード200 OKDEPLOY.mdに「2回ハマった」と明記して再発防止
7動画レンダリングPlaywrightでスクリーンショット撮影Playwright未インストールプロジェクトのnode_modulesにない
8インストール後に再実行ffmpegにlibx264なし+音声パス取得失敗デコーダーのみビルド。audio.srcは再生しないと空
9音声パスをデータファイルから直接取得動画生成OK、全セリフ2秒固定ffprobeがなくfallback値が使われた
10WAVヘッダーから音声長を直接計算正確な長さで動画完成ffprobe不要でWAVヘッダーパースが軽量
11TTS二重管理Pythonスクリプトにセリフをハードコードts修正のたびにPyも手動更新が必要Source of Truthが2箇所は破綻する
12ts→JSON変換ステップを追加PyがJSONを読む一本化フロー完成言語をまたいでもパイプラインで繋げば一元管理可能
13音声ファイル配置public/audio/に配置gitignoreでデプロイに含まれないリポジトリも肥大化する
14audio-assets/に移行+dev middlewareローカルOK、本番はR2配信composableで環境切り替えが正解
15ナレーション移行AI任せで旧→新プロジェクトに移行メッセージラインがほぼ全面書き換えられていたAIは原文を勝手に「改善」する。忠実移行を明示指示すべき
16旧プロジェクトの原文を忠実に全復元Chapters 1-4の整合性回復補足はナレーション層で行う方針に

今日の学び

  • ElevenLabs v3のAudio Tagsは文中挿入で感情の切り替えが効く。GCP TTSのSSMLより表現力が高い
  • wrangler r2 object put はデフォルトでローカルエミュレータに書き込む。本番R2には --remote フラグが必須(2回ハマった)
  • TTS生成スクリプトのSource of Truthは1箇所に。ts→JSON変換パイプラインで二重管理を排除
  • WAVヘッダーを直接パースすればffprobe不要で音声長が取れる
  • ロジックを純粋関数に抽出するとVue依存なしでテストが書ける

明日やること

  • 命名規則移行計画(Section > Chapter > Topic)の実装に着手
  • ElevenLabsの残クレジットでChapter 01の音声も差し替え検討
  • 動画レンダリングスクリプトの改善(既存音声ファイルを使う方式に統一)
  • ナレーションレビューで指摘した残りの用語解説追加

関連記事