ビジネスAIプラン|システム解説

画面収録を1本投げると、
編集済みのPremiereプロジェクトが出てくる仕組み

Claude Code で組んだ動画編集の自動化パイプラインを、実装レベルで解説します。 動画編集の話に見えますが、本質は「自分が毎回やっている手作業を、どう仕組みに移すか」です。 その型はそのまま、皆さんの別の作業にも使えます。

実測に使った素材:32分51秒の画面収録(1.76GB)/ 出力:26分22秒のカット済みタイムライン+編集者用ZIP
構成:33スクリプト・中核の cut-apply だけで1,038行
目次
  1. 全体像 — 何が入って何が出るか
  2. 設計の芯 — なぜ「動画を作らない」のか
  3. ジェットカット — 無音・非発話・フィラー・AI判断の4層
  4. テロップ — 日本語を「どこで切るか」を機械で守る
  5. モザイク — OCR×正規表現で秘密を自動で塞ぐ
  6. トピックカード — 番組らしさを1ファイルで足す
  7. キャラクター — 口パクを音声解析なしで作る
  8. リテンション — 「何も変わらない30秒」を機械が見つける
  9. エディター配布 — リンク切れを構造的に潰す
  10. 持ち帰ってほしい設計の型

01全体像 — 何が入って何が出るか

入力は画面収録のmp4が1本だけです。カットもテロップも何もしていない、撮ったままのファイルを置きます。 出力は「編集済みの動画」ではなく、Premiere Proにそのまま読み込めるプロジェクト一式です。

収録した mp4(32分51秒)
  │
  ├─ preprocess ──→ 音声を抜いて正規化・無音を検出・文字起こしを用意
  │                  audio_normalized.wav / silences.json / transcript.json
  │
  ├─ cut-analyze ──→ フィラー(えー、あのー)と どもり を機械検出
  │                  filler_cuts.json / cut_review.md
  │
  ├─ AI判断(Claude)→ 言い直し・失敗テイク・冗長を読んで判断
  │                  ai_cuts.json + テロップの誤認識を校正
  │
  ├─ cut-apply #1 ─→ カット計画を確定(ここでテロップのlintが走る)
  │                  cut_plan.json … 1971.7秒 → 1582.2秒 / 132クリップ
  │
  ├─ plan-scaffold ─→ オープニング・スライド・インサート・Bロールの計画
  │
  ├─ retention ────→ 「30秒以上なにも変化しない区間」を検出して演出を提案
  │
  ├─ character ────→ 右下のキャラを口パクさせてアルファ付き動画に
  │
  ├─ cut-apply #2 ─→ 全トラックを配線
  │                  Telops / Topic / Character / Slides / Inserts / Broll / Mosaic
  │
  ├─ program-gate ─→ 必要な素材が全部あるか機械が検査(無ければ止まる)
  │
  └─ editor_package → 編集者へ渡す単一ZIP(XML+参照素材+リンク修復ツール)
32:51 → 26:22今回の実測(6分29秒短縮)
132生成されたクリップ数
27自動でぼかした箇所
54テロップの校正件数

02設計の芯 — なぜ「動画を作らない」のか

このパイプラインは、最終的な動画ファイルを書き出しません。出すのは Premiere が読む timeline.xml(Final Cut Pro 7 XML・xmeml v4形式)と、それが参照する素材です。

理由は3つあります。

理由中身
直せる焼き込んだ動画は直せない。XMLなら編集者が1カットだけ動かせる。AIの判断が外れた箇所を人が上書きできる
速い32分の動画を書き出すと数十分かかる。XMLなら数秒。試行錯誤の回転が段違いに上がる
渡せる編集者は普段のPremiereで作業できる。専用ツールを覚えてもらう必要がない

ここが応用の要です。「AIに最後までやらせる」と考えると、人が直せない成果物ができます。 AIには"人が直せる中間物"まで作らせて、最後の判断を人に残すと、精度が足りなくても実用になります。 このパイプラインが実務で回っているのは、AIが賢いからではなく、外したときに直せる形にしてあるからです。

設定は1ファイルに集約する

フォント・色・サイズ・AIの生成指示まで、見た目に関わる値はすべて config/style.json にあります。 コンポーネントやスクリプトを直接書き換えることは禁止にしています。

pipeline.silenceNoiseDb        = -30     # これより静かなら無音とみなす
pipeline.silenceMinDurationSec = 0.45    # 0.45秒以上続いたら無音区間
pipeline.jetcutPadSec          = 0.1     # 切り口の前後に残す余白
pipeline.jointFadeMs           = 12      # 繋ぎ目の音のフェード
pipeline.cut.minKeepSec        = 0.45    # これより短い"残し"は作らない
pipeline.cut.maxAiCutRatio     = 0.25    # AIが切ってよい上限は全体の25%まで

最後の maxAiCutRatio が効きます。AIが暴走して動画の半分を削る事故を、構造的に防ぐためのものです。 AIに判断させるなら、判断できる範囲そのものに上限を置く——これは動画に限らず使える考え方です。

03ジェットカット — 4つの層が別々に効く

「無音を切る」だけだと、実際には使えません。喋っていない映像、言い淀み、言い直しは無音にならないからです。 このパイプラインは4つの層で別々に判定します。

層何を切るか判定の方法今回の実測
① 無音音が止まっている区間ffmpeg の silencedetect(−30dB・0.45秒以上)91.0秒
② 非発話音はあるが喋っていない区間文字起こしの語の時刻と突き合わせ、語が無い区間を検出214.0秒
③ フィラー「えー」「あのー」やどもり語彙辞書+前後の間の長さで孤立度を判定14.6秒
④ AI判断言い直し・失敗テイク・冗長Claude が文字起こし全文を読んで判断69.9秒

注目してほしいのは②が一番大きいことです。無音カットだけの自動編集ツールは多いですが、 実際の画面収録で一番多いのは「操作しながら黙っている時間」です。これは音があるので無音検出では取れません。 文字起こしの単語ごとのタイムスタンプを持っているから、ここを切れます。

④ AI判断は何をしているか

機械が判定できない領域だけをAIに回します。AIに渡すのは cut_review.md という中間ファイルで、全セグメントが時刻つきで並び、機械が拾った候補に印が付いています。

[# 34  180.44- 185.86] あとは僕自身サムネイルとかアイキャッチ画像を作る (→間24.58s)
[# 35  210.44- 214.74] 作る方法であったり仕組み、あとは僕自身がですね

「作る」で切れて24.58秒の間があり、次で言い直している——これは機械には判定できません。 AIは ai_cuts.json に理由つきで書きます。

{"startSec": 180.44, "endSec": 185.86, "kind": "retake",
 "reason": "「作る」まで言って24.58秒の間。#35が言い直しているので言いかけ側を落とす"}

理由を必ず書かせるのが肝です。後から「なぜここが切れたのか」を人が検証できます。 今回の実測では、終盤で締めの挨拶を4回言い直しているのをAIが見つけ、最初の1回だけ残しました。

応用できる型 機械で判定できるものは機械に、できないものだけAIに。 全部AIに投げると、遅く・高く・ブレます。無音検出は ffmpeg が確実にやるので、AIは 「文脈を読まないと分からないこと」だけを担当します。そしてAIの判断には必ず理由を残させ、上限を設ける。

04テロップ — 日本語を「どこで切るか」を機械で守る

全発話にテロップを入れる方針(フルテロップ)です。問題はどこで改行するかで、 ここが雑だと一気に素人っぽくなります。

悪い例:

❌  「実際にどのような形でサムネイルを作ってきたかみたいな感じの」
    「苦労話を」                ← 短すぎる断片
    「交えて実際に結構大事な」

これを防ぐため、BudouX(Googleが公開している日本語の文節分割ライブラリ)で文節を認識したうえで、 8種類のlintルールを機械でかけています。

ルール検出する崩れ強さ
short-fragment断片が短すぎるhard(止まる)
no-before-noun「〜の」で行が終わり、次が名詞soft(警告)
head-particle行頭が助詞で始まるsoft
adnominal-tail連体修飾で行が終わるsoft
predicate-tail述語の途中で切れるsoft
compound-split複合語が途中で割れるsoft

hard違反が1件でもあると cut-apply が止まります。納品基準は0件です。 今回も実際に1件で止まり、直してから先に進みました。

校正で語を落としてはいけない

AIは文字起こしの誤認識も直します。今回は40箇所を校正しました。

瀬野アオ        → セナオ          ← 名前の誤認識(公開面に出るので最重要)
2Dカテゴン風    → 2Dカートゥーン風
相決画像        → 素材画像
周囲化を目的    → 収益化を目的
キャンバー      → Canva
クロードコード  → Claude Code
実際にやらかした失敗 校正のとき、読みやすくしようとして語を削ると、画面と音がズレます。 テロップは音声のタイムスタンプに紐づいているので、縮めた分だけ後ろが前倒しになるからです。 今回 short-fragment 違反を直したときも、「の」を削除せず次の行頭へ移動しました。 校正は「置き換え」だけ。削除と要約は禁止——これは何度か失敗してから機械の検査項目にしました。

05モザイク — OCR×正規表現で秘密を自動で塞ぐ

画面収録をそのまま出すと、APIキー・メールアドレス・本名・ファイルパスが映り込みます。 1回でも出せば取り返しがつきません。ここは人の注意力に任せず、機械で塞いでいます。

動画 ──1fpsでフレーム抽出──→ PNG(1,972枚)
        │
        ├─ OCR(macOS Vision・無料・画面の文字に強い)
        │    ※ Tesseract へのフォールバックあり
        │
        ├─ NGパターン照合(20パターン)
        │    正規表現8種:メール / OpenAIキー / Google APIキー / AWS /
        │                 GitHubトークン / Slackトークン / Bearer / 電話番号
        │    + ローカル辞書(本名など・git管理外に分離)
        │
        ├─ スパン統合(連続するヒットを1区間にまとめる)
        │    検出43件 → 27スパン
        │
        └─ mosaic_review.md(チェックボックス+サムネ画像つき)
             既定は全件 [x]=安全側。確認して --approve で確定

設計で効いているのは次の3点です。

1. OCRに macOS Vision を使う

クラウドのOCRに画面を送ると、秘密を隠すために秘密を外部送信することになります。 macOS 内蔵の Vision なら、ローカルで完結し、無料で、画面の文字に強い。

2. 既定を「全部ぼかす」にする

レビューファイルは最初から全件チェック済みで生成されます。人は「外す」判断だけをする。 逆(既定OFFで必要なものを選ぶ)にすると、見落としがそのまま漏洩になります。

3. 秘匿必須には上限を適用しない

演出を塞がないよう自動適用には件数上限がありますが、本名・APIキー・手動指定は上限の対象外で必ず全件適用されます。 今回も「秘匿必須25件は上限の対象外として全件適用」と出ています。

今回の実測と、そこから得た教訓 今回は本名41検出・メールアドレス2件が見つかり、27スパンに統合して全件ぼかしました。 中身は、デモ用に作ったフォルダのパスがアプリのログ行として画面に出ていたものです。 「デモのために一時的に作ったもの」が一番危ない——本番の資産は気をつけますが、 その場しのぎで作ったフォルダ名は無防備になります。以後、配布物のデモは本名を含まないパスに置くルールにしました。

なお本名などの語は ng_keywords.local.txt / ng_patterns.local.json という ローカル専用の辞書に分離し、git管理外にしています。検査ルール自体をリポジトリに置くと、 そこから秘密が漏れるためです。

06トピックカード — 番組らしさを1ファイルで足す

画面右上に出る「トピック|◯◯ / 内容|◯◯」のカードです。テレビ番組の画面構成を真似たもので、 視聴者が途中から見ても何の話か分かるようにする役割があります。

仕組みは拍子抜けするほど単純です。work/<name>/topic_title.txt に2行書くだけ。

サムネ自動生成
動画を入れるだけ

このファイルが存在すれば、cut-apply が Topic トラックとして自動配線します。 ラベルの「トピック|」と「内容|」はコンポーネント側が付けるので、中身だけ書きます。制約は各行14字以内・体言止め・句読点なし。

文言は文字起こしからAIが自動で決めます。直したければ、テキストファイルを書き換えて cut-apply を再実行するだけ(1〜2分)。

「ファイルの有無で機能をON/OFFする」——この設計はパイプライン全体で使っています。 character_mode.txt に on と書けばキャラが出る、topic_title.txt があればトピックが出る。 設定画面もフラグ管理も要らず、人もAIも同じ方法で操作できます。

07キャラクター — 口パクを音声解析なしで作る

画面右下でキャラクターが喋りに合わせて口を動かします。普通なら音声解析(Rhubarb など)が要りますが、 既定では音声を解析せずに作っています。

viseme-from-text 方式

すでに単語ごとのタイムスタンプ付き文字起こしを持っているので、これを使います。

  1. 各単語の開始・終了時刻を取る
  2. その語のモーラ数(かなの拍数)で区間を等分する
  3. 各モーラに口の形(viseme)を割り当てる
  4. 無音区間は口を閉じる

結果は Rhubarb 互換の mouth_cues.json になります。外部API不要・追加依存ゼロ・処理は一瞬。 精度が要る回だけ --engine rhubarb で本物の音声解析に昇格できます。

レンダリングはアルファ付き ProRes 4444(character_layer.mov)で書き出し、 cut-apply が Character トラックとして重ねます。

OOMで5連続クラッシュした話 当初は全尺を1回のレンダリングで処理していました。34分の素材で5回連続、OSにプロセスを殺されました(メモリ不足)。 長尺だとヘッドレスChromeが持たないためです。

対処は1,500フレームごとのチャンク分割です。チャンクごとにChromeを使い捨て、 最後に ffmpeg で無劣化結合(-c copy)します。さらに完成済みチャンクはマニフェスト照合して再利用するので、 途中でクラッシュしても続きから再開できます。

ここで学んだのは、「長時間かかる処理は、必ず途中で死ぬ前提で作る」ということです。 分割して、途中結果を保存して、再開できるようにする。これはAIのバッチ処理全般に効きます。

08リテンション — 「何も変わらない30秒」を機械が見つける

視聴維持率が落ちるのは、多くの場合画面に変化がない時間です。 人間は自分の動画を見ていると気づきにくいので、機械に探させます。

やっていることはシンプルで、タイムライン上の「変化イベント」を全部集めて、間隔を測るだけです。

集めるイベント出どころ
カットの継ぎ目cut_plan.json の各クリップ境界
強調テロップtelop_keywords.json
スライド挿入slides_plan.json
定型インサートinserts_plan.json

これらを時刻順に並べ、30秒以上イベントが無い区間を「変化なし」として検出します。 そして区間ごとに、ズーム・効果音・スライド・Bロールのどれを入れるべきかを提案します。

提案は自動適用されます(既定で最重要2件まで。上限は「演出を塞がない」ための調整弁)。 残りはレビュー表に出るだけで、人が選べます。

ここも応用が効きます。「良くする」のは難しいですが、「悪い状態を機械的に定義する」のは簡単です。 "面白い動画"は定義できませんが、"30秒何も変化しない"は測れます。 自分の作業でも、良さを測ろうとせず、避けたい状態を1つ数値で定義すると、そこから自動化が始まります。

09エディター配布 — リンク切れを構造的に潰す

最後に、外部の編集者へ渡すZIPを作ります。ここが一番地味で、一番事故が起きるところです。

XMLプロジェクトの根本的な弱点

timeline.xml は素材を絶対パスで参照します(pathurl)。 自分のMacのパスが書かれているので、そのまま渡すと編集者の環境では全部リンク切れになります。 しかも「どの素材が必要か」は人間には追えません(今回は132クリップ+テロップ+キャラ+モザイク)。

マニフェスト駆動で解決する

  1. XMLが参照している全 pathurl を正として素材をコピーする
    (フォルダを丸ごとコピーするのではなく、XMLから逆算する。参照元が存在しなければ即エラーで止める=欠品が構造的に起きない)
  2. 同梱するXMLの pathurl を中立パス(file://localhost/PKG/素材/…)に書き換える
    (制作マシンの絶対パス=本名を含むパスを配布物に残さない、という意味もあります)
  3. 「リンクを直す.command」を同梱する
    編集者がダブルクリックすると、その場所の絶対パスへ書き換え+全素材の実在を検証。何度実行しても同じ結果になる(冪等)
  4. ng_check(禁止語検査)を通してからZIPを生成する
    検査に落ちたらZIPを作らない。配布物に本名が残る事故を機械で止める

単一ZIPにしているのも理由があります。Google Drive はフォルダをダウンロードすると約2GBごとに複数ZIPへ分割され、 素材が散ってリンクが壊れます。これは実際に起きた事故で、以後「受け渡しは必ず単一ZIP」に固定しました。

program-gate — 渡す前に機械が検査する ZIPを作る前に、オープニング・スライド・インサート・リテンション適用・トピックバナーが 実在するかを機械が検査し、足りなければ止まります。

これは3回連続で「オープニングが無音のまま納品された」ことから作った門です。 手順書に「必ずやること」と書いても守られなかったので、機械が止める形にしました。

10持ち帰ってほしい設計の型

動画編集の話をしてきましたが、効いているのは動画固有の技術ではありません。 次の6つは、皆さんのどんな作業にも当てはまります。

型このパイプラインでの現れ方皆さんの作業なら
人が直せる中間物を作る動画ではなくXMLを出す清書ではなく下書きを出させる。最後の判断は自分が持つ
機械とAIを分業する無音はffmpeg、文脈はAIルールで決まることはAIに投げない。安く・速く・ブレない
AIの裁量に上限を置くAIが切れるのは全体の25%まで「AIが勝手に変えてよい範囲」を先に数値で決める
判断には理由を残させる各カットに reason 必須後から検証できない自動化は、事故が起きたとき直せない
悪い状態を数値で定義する「30秒変化なし」を検出良さは測れなくても、避けたい状態なら測れる
守らせたいことは機械で止めるlint・program-gate・ng_check手順書に書いても守られない。止まる仕組みにする

最後にひとつ

このパイプラインは最初からこの形だったわけではありません。 オープニングを3回無音で納品し、キャラのレンダリングで5回OOMを起こし、テロップの校正で音とズレを作りました。

今ある検査項目は、そのほとんどが実際に失敗してから足したものです。 逆に言えば、仕組みは失敗するたびに強くなるということです。

最初から完璧に設計しようとせず、失敗したらその場で「同じ失敗を機械が止める形」に変える。 これを繰り返すだけで、半年後には人が注意しなくても品質が保たれる状態になります。