Excel講座の本人音声を全編再合成した日:読み上げ台本を「耳で分かるか」でレビューし、聞いた感想を区間単位で直す

開発eurekapu-nuxt4

Excel講座の本人音声を全編再合成した日

前日は、Excel基礎講座(eurekapu-nuxt4)のナレーションを本人の声で合成し、Mac にも一部を任せた(前日の分担設計)。 この日は、章ごとの本人音声で講座の全編を合成し直す。 計画書に分担まで書いてあったので、そのとおりに分担させればいい、と思っていた。

Windows 1台なら9時間

計画書を読ませると、Windows(RTX 3070)が分量の多い4セクションを持つ分担になっていた。 Mac 側のセッションから接続先が届き、Windows から SSH でつながった。 ところが Mac のリポジトリは2つとも古かった。 計画書はすでに push 済みだったので、Mac のセッションに pull を頼むだけで済んだ。

そもそも Windows 単体だと何時間かかるのか、と聞いた。 答えは、合成だけで約8時間半〜9時間。 前日に実際に合成したときの所要時間から出した数字である。 それなら分けよう、と準備を頼んだ。

準備では、合成スクリプトを改修してもらった(approved.json の検証、参照音声の中身のハッシュによるキャッシュ、途中ファイルへの対策)。 参照音声は12セットとも、録音ページの fingerprint と一致した。 台帳は Windows が2,626文(約4.2時間)、Mac が2,405文(約3.9時間)とイントロ、全体で188ジョブになった。

このあいだ、同じリポジトリでは別のセッションもコミットしていた。 package.json などがステージされていたので、自分の4ファイルだけを指定してコミットさせ、別のセッションのコミットが終わるのを2度待った。 Windows の合成が走り出し、台帳を Mac に送ってハッシュの一致を確かめてから、Mac のセッションにも実行を頼んだ。

合成とレビューの順番が逆だった

報告の最後には、生成スクリプト全体のレビューを Opus のサブエージェントに進めさせている、とあった。 まず気になったのはモデルで、5.5 になっているかを聞き、5.5 にして、と頼んだ。 Agent ツールで指定できるのは opus という別名だけで、5.5 を明示する方法はないという。 そこで、親セッション(Opus 5.5)のモデルを必ず引き継ぐ fork 型で起動し直させた。

次に引っかかったのは順番である。 スクリプトをレビューさせているのに、合成を先に進めているのか。 答えは「はい」で、Claude Code が私に確認せずにその順番を選んでいた。

ここで、そもそもの食い違いに気づいた。 見てほしかったのはコードではなく、読み上げ台本の文字列だけだった。 基準も伝えた。 ポッドキャストで聞くように、音声だけで独立して成り立つか。 誤字脱字は当然だめで、それより、耳で聞いて分かりにくい言い回しをやめてほしい。

コードを読み始めていたエージェントは止めた。 合成も止めさせた。 TaskStop では子プロセスが残ったので、プロセスを直接止めている。 Windows は4ジョブ終わった時点で止まり、Mac も止めた。

耳だけで分かるかを5体で読む

台本は、台帳に固定した188ジョブ分のクリップから、1,000文前後ずつ5つに分けて書き出させた。 fork 型のエージェント5体を並列で走らせた。

担当範囲指摘
1関数の活用の前半(190クリップ)21件(high 1、medium 12、low 8)
2関数の活用の後半と関数概要(181クリップ)22件(high 0、medium 12、low 10)
5小さい章、top、イントロ34件(high 1)

報告の冒頭に書かれたモデルは claude-opus-5-5 で、指定どおりだった。 担当5の high は、Stream Deck の章で「四つのお題」と言っているのに、読み上げる項目が三つしかないという指摘である。 事実に関わる指摘は、画面のデータと照合させてから確認ページにまとめてもらった。

判断が要るのは136件だった。 講座全体の食い違いが3件、個別の指摘が133件である。 全部答えるから、この判断を音声読み上げのスキル(tts-narration)のリファレンスに残しておいて、と頼んだ。

回答を待つあいだに、採用した直し案を台本の元データへ当てはめるスクリプトを用意させた。 全件採用と仮定した試験で、133件すべての当てはめ先が1か所に決まることを確かめてある。 回答を反映したあとも、次の2点を確かめさせた。

  • 合成の上限(1文約30秒)を超えそうな長い文ができていないか
  • レビュー担当が「画面との照合が必要」「推測」と書いた項目47(カンマ二か所)と項目67(売上の区分)が、画面と合っているか

判断の記録は references/ear-review.md として新しく作り、SKILL.md の §0 に導線を1行足した。

合成の再開とイントロ

台本の修正をコミットして、両機の合成を再開した。 Mac は11:48に再開した。 87ジョブのうち完成済みの1ジョブは、台本が変わっていなかったのでそのまま使われた。

イントロは専用の合成スクリプトを書かせた。 62段落を170文に分け、最長56字、シードは170文すべてで重複しない。 Mac には、87ジョブが正常に終わったら自動でイントロを始めるよう予約させた。 GPU の合成が2本同時に走ることはない。

途中で進み具合を聞くと、Windows は101ジョブ中8ジョブ、2,660文中201文(約8%)だった。 見込みは Windows が16時ごろ、Mac がイントロの約20分を足して16時〜16時半ごろ。

差し替えの前に、対象の現行ファイル1,133件をコピーしてハッシュを記録させた(2.2GB)。 基本機能の音声2,595ファイルのハッシュも記録し、統合後に一致するかを照合する。 イントロは170文中40文まで進み、1文あたり約8.5秒だった。

聞いたら記録を残したい

Windows の分は完成音声に差し替え済みで、dev サーバーの制作画面(動画プレビュー)で聞ける。 聞きながら、音声をチェックしたことを自分で確かめられる印がほしくなった。 チェックマークと、チェックした日時。 記録は Cloudflare 側に保存してほしい、と頼んだ。

既存の D1 に表を1つ足す形になった。 リモートの D1 への接続が一度権限エラー(7403)になり、どの認証でつながっているかを確かめてから、migration の 0010 だけを新しく適用した。 ヘッダーの「1920 × 1080」の横にチェックボタンと日時を置き、左の一覧に「聴」の印を出す。 テンプレートが「閉じタグが不正」で落ちたのは、Edit ツールの編集で <a :href のスペースが消えていたせいだった。 保存と日時の表示(2026-09-23 15:15)を確かめ、確認用のチェックは外させた。 テストは13件すべて通った。 この時点で、11セクションすべての音声が新しい声に差し替わっている。

続けて、制作画面の説明文(枠の中がそのまま動画になる、という案内)を消して、そこにフィードバック欄を置くよう頼んだ。 保存先はやはり D1(0011)で、あとから Claude Code が取り出せるようにする。 「音声チェック」ボタンは「完了」チェックに名前を変えた。

最初のフィードバックは15:57:42に保存した。 絶対参照と相対参照の概要の区間(functions-c00-s00)で、ページの一覧を「一つ目は…二つ目は…十個目は」と番号で全部読み上げていて、口語として不自然になっている。 136件を判断して直した台本でも、耳で聞くとここが引っかかった。 取り出せることを確かめ、修正は次のセッションに引き継いだ。

1区間だけを作り直す

16時のセッションでは、過去の判断記録に前例がないことを確かめてから、章の概要表の先頭に「No.」列(1〜10)を足させた。 読み上げは「最初は → 次は → 続く三ページは → その次の二ページは → 最後は」でつなぐ。 直したのは台本のデータファイル1本だけである。

台帳は全ジョブを列挙し直す形だが、実行スクリプトは台本の文を manifest と突き合わせて完成済みを判定する。 101ジョブのうち100件は飛ばされ、c00-s00 だけが72秒で作り直された。 検査は、プロジェクトの venv に numpy がなかったので、Irodori-TTS の環境で回させた。 中身が変わる9ファイルだけを退避して差し替え、基本機能の2,595ファイルのハッシュが一致することも見てもらった。 区間の長さは134秒から132秒になった。

画面を見ると、No. 列が表の約3分の1を占め、ページ名の列を押しつぶしていた。 原因は、表示用 CSS のこの1行だった。

th:first-child{width:45%}

先頭の列に効かせていた幅が、新しく先頭に来た No. 列に当たっていた。 直したあとは No. 列が細くなり、ページ名が1行に収まった。 講座ページのほうでも No. 列が出て、音声は2:12だった。 差分は表11行と読み上げ8行の19行だけで、そのままコミットさせた。

もう1つ頼んだ。 完了した区間には「完」の印が付くが、フィードバックした区間にも、カタカナの「フ」を赤マゼンタで囲った印がほしい。 サイドバーの一覧で「完」の隣に、同じ大きさのマゼンタ枠の「フ」が並んだ。

印の API を試した時点で、新しいフィードバックが4区間に届いていた(c00-s02、c00-s08、c00-s10 に3件、c01-s00)。 c00-s02 は GIF の扱いについての指摘で、動く版の GIF は 404 で消えていた。 探させると Dropbox に候補が見つかった。 ただ、それは前日にこのプロジェクトから書き出した MP4 で、元の素材ではなかった。 計画書に進捗の §9 を足し、翌日のタスクを Google Tasks に登録した。

前日の積み残しと、赤いままだった CI

合間に、前日の連鎖処理で R2 に上がりきっていなかった分も片づけた。 章3の音声が R2 に上がっているかを公開 URL への HEAD リクエストで全数確かめさせ、未反映の124ファイルを上げて、監査の結果は0件になった。 このときのメモリの空きは 11.4GB / 32GB。 計画書の HTML では、表が本文幅(860px)に縛られていた。 表だけを本文幅から切り離すルールを共通 CSS(md-preview.css)に足させると、進捗表は1216px 幅で、右の目次と重ならずに描画された。

GitHub Actions が失敗している、という表示も調べさせた。 止まっていたのは依存パッケージのインストール段階で、ERR_PNPM_LOCKFILE_CONFIG_MISMATCH(overrides の設定が lockfile の記録と一致しない)が出ていた。 推奨案で直して CI が通るまで見て、と頼んだ。

インストールが通ると、その後ろに隠れていた問題が順に出てきた。

  • Build:Git 管理外(R2 側)の画像への参照。ほかのページと同じ :src バインディングに揃えた
  • Unit tests:9/11 のコミットで章0の比較図を After だけに替えたのに、テストが古いままだった
  • Unit tests:CI は LFS なしでチェックアウトするので、比較対象の SVG が LFS のポインタ文字列になっていた。チャートの SVG 10本だけを取得する手順を足した(リポジトリの LFS ファイルは4,380本)
  • E2E:2件の失敗

最終的に 5d958bba で E2E まで全ステップが通った。 CI が通ったのは 07-28 以来である。 インストールの失敗が5つの問題を隠していて、5コミットで1つずつ直した。

途中、コミットレビューで Codex が high と判定した指摘があった。 Claude Code は、今の lockfile に該当する esbuild はないので medium と判定し直したうえで、1行で済むからとバージョン範囲を元に戻していた。 報告が英語で返ってきたので、日本語にして、と2回言っている。

同じセッションで、ある資格講座のページの画像も R2 に上げさせた。 606ファイル中14ファイルが R2 になく、うち13枚は公開中のページでも使われていた。 アップロード直後は13枚が 404 のままで、CDN のキャッシュを疑って Cloudflare のダッシュボードを開かせた。 しばらくすると CDN が 200 を返すようになり、14枚すべてがローカルのファイルとバイト数まで一致した。 手動のキャッシュ削除は要らなかった。

学びメモ

  • 「スクリプト」という一語で、私は読み上げ台本の文字列を、Claude Code は生成スクリプトのコードを思い浮かべていた。合成とレビューの順番も、確認なしに決まっていた。食い違いに気づいたのは、順番を聞いたときだった。
  • 実行スクリプトが台本の文で完成済みを判定するので、フィードバック1件の修正は101ジョブ中1ジョブ、72秒の作り直しで済んだ。差し替えの前には中身が変わる9ファイルだけを退避し、差し替えたあとで基本機能のハッシュを照合した。

文字の上で136件を判断した台本は、耳で聞いた最初の区間で番号の読み上げに引っかかった。 翌日に回した4区間のフィードバックは、まだ直していない。

#Irodori-TTS#音声合成#Excel講座#Claude Code#サブエージェント#Cloudflare D1#GitHub Actions