Communitygithub.com

ThomasHMD/rough-cut

Premiere Pro 向けトーキングヘッド映像(モノローグ、スピーチ動画)の自動粗編集。リテイク、言い間違い、つまずき、フィラーワード、長い沈黙を除去した Final Cut Pro 7 XML(XMEML)タイムラインを生成します。元のクリップは一切変更しません。

rough-cut とは?

rough-cut は、Premiere Pro でトーキングヘッド形式の映像を粗編集するための AI エージェントスキルです。このスキルは、クリップそのものは一切変更せず、リテイク、言い間違い、つまずき、フィラーワード、長い沈黙を自動的に除去した編集済みタイムライン(Final Cut Pro 7 XML / XMEML 形式)をクリップの隣に生成します。ユーザーは Premiere Pro でクリップの文字起こしを行い、プロジェクトを保存した後、Claude にクリップのパスと参照スクリプト(任意)を渡すだけで、3 ステップで完了します。スキルは言語ファイル(英語、フランス語内蔵、追加可能)を用いて言語固有の処理を行い、Pipeline v2 では Premiere Pro のトランスクリプトを主ソースとして用い、Whisper によるセカンドオピニオンと Claude による意味解析を組み合わせることで高い精度を実現します。最終的な編集結果は XML として書き出され、Premiere Pro にインポートするだけで、リテイクや不要部分が除去された「Derush_vN」シーケンスが使用可能な状態で表示されます。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ThomasHMD/premiere-rough-cut/tree/HEAD/skills/rough-cut

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

rough-cut:Premiere Pro 向け自動粗編集

ワンタイムセットアップ:キットルートの INSTALL.md を参照してください。プラグインを使用する場合のセットアップ行は「bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}"」です。手動インストール(4つの skills/ フォルダを ~/.claude/skills/ に並べてコピー)の場合は、キットルートで bash install.sh を実行します。スクリプトはこのスキルの scripts/ フォルダにあります。

適用範囲

  • 対応:リテイク、言い間違い、つまずき、フィラーワード、長い沈黙が除去された Final Cut Pro 7 XML(XMEML、.xml)のタイムライン。マークダウンレポート。判断が残っている部分を示す赤いマーカー。
  • 非対応:クリップの変更、トランスコード、ビデオの書き出し、カラーグレーディング、ミキシング、明らかな言い換えを超えたテイク間の選択(これは編集者の判断です)。

基本ルール:元のクリップは決して変更されない

スキルはクリップの隣にのみ以下のファイルを書き込みます:

  • <clip>_Derush_v1.xml:取り込む編集済み XML(FCP7 / XMEML)
  • <clip>_Derush_v1.report.md、<clip>_Derush_v1.log.txt
  • <clip>_Derush_v1_work/:保持されるワークフォルダ(トランスクリプト、中間カット)

XML は絶対パス(file://localhost/...)でクリップを参照します。Premiere はそれを参照するだけです。新しいパスを実行すると、v2、v3… が作成され、何も上書きされません。

ユーザーが行うこと(3ステップ)

  1. Premiere で:クリップを読み込み、文字起こしを実行し(テキストパネル > 文字起こし)、プロジェクトを保存します。トランスクリプトは .prproj ファイル内に保存されます。ユーザーにそれをエクスポートするよう依頼しないでください。
  2. Claude にクリップのパスと、動画の参照スクリプト(プレーンテキスト、Markdown、Google ドキュメント、Notion ページなど、読み取り可能なもの)があればそれを渡します。スクリプトは、繰り返しが意図的なものかどうかを判断するためだけに使用されます。スクリプトがなくても動作し、その場合は意図的な繰り返しはカットではなくフラグとして扱われます。
  3. .xml を読み込みます(ファイル > 読み込み)。「Derush_vN」シーケンスが表示され、すでに編集されています。カット部分はタイムラインから削除され(クリップは連続して配置され、詰める必要はありません)、疑わしい部分はアクティブなクリップとして赤いマーカーとともに残ります。

その他は何も尋ねないでください。言語、クリップタイプ、オプションは推測されます(下記参照)。質問が必要なのは、クリップタイプが本当に曖昧な場合のみです。

言語

言語固有のすべて(フィラーワード、言い間違いの定型句、スレートパターン、孤立した接続詞、カットする冒頭部、ホールシネーションハルシネーション、マーカーの理由テキスト)は languages/<code>.json にあり、コード内には決してありません。フランス語(fr)と英語(en)が組み込まれています。言語は --lang <code> で選択され、指定がない場合はトランスクリプトに記録された言語が使用され、それもない場合は en が使用されます。詳細と言語の追加方法:references/languages.md

Pipeline v2:テイク選択(通常ルート)

欠陥のみを検出する v1(下記)では、リコール率が約 57% で頭打ちになります。その理由は、Whisper が繰り返されたテイクを自動的に重複除去するためです。そのアンチループデコーダーは、単語単位で繰り返された文をハルシネーションとして扱い、1回だけ書き起こします。これは設定では修正できません。Premiere のトランスクリプトはすべてのテイクを単語単位で保持し、その単語の開始位置は長い無音の後でもずれません(Whisper はずれます)。したがって:

ステップツール役割
1extract_prproj_transcript.py project.prproj words_premiere.json [--rush CLIP.MOV].prproj から words_premiere.json へ(主要ソース)。プロジェクトにトランスクリプトがない場合は終了コード 2:ユーザーに文字起こしの実行とプロジェクトの保存を依頼します。フォールバック:手動 JSON エクスポートに対する parse_premiere_transcript.py
2extract_audio.py + transcribe.pyWhisper = セカンドオピニオン(テキストの相互確認、境界は対象外)
2bcalibrate_premiere_times.pyPremiere のトランスクリプトをオーディオに再調整します。すべてのラフカットで、オーディオ抽出の直後に実行します(トランスクリプトが時間通りであれば何も変更しません)。オフセットをウィンドウごとの相互相関で測定します。21分のクリップの最後で 1.8 秒のずれが確認されています。忘れた場合の症状:silence_cuts.py が数十の「不審なノイズ」を報告する
3Claude in context意味解析:Premiere のトランスクリプトとスクリプト、Whisper を比較してリテイク、言い間違い、つまずきを特定します。ルールは下記
4silence_cuts.pyPremiere の単語間での 1.0 秒以上の無音、音声レベルに再調整された単語終了、列挙ガード(2つの短いブロック間の短い間隔 = 意図的なリズム)、ノイズゾーン:フラグまたはカット(下記参照)。デフォルト値は完成した編集に対して調整されています。再測定せずに変更しないでください(references/lessons.md、「測定」を参照)
5apply_takes.py <work>ステップ 3 で決定されたテイクが takes.json に書き込まれます(単語インデックス、手動の境界または秒単位のカットはオプション)。スクリプトはエネルギー谷に境界を設定し、無音と統合し、2つのカットの間に残ったミュートフラグメントを融解し、すべてのクリップエッジを実際の音に再調整し、クリップエッジの 0.25 秒未満の孤立した音をフラグし、cuts_final.json を書き込みます。protect(無音を保持)はユーザーが要求した場合のみ
6build_premiere_xml.pyXMEML。オプション meta["audio_file"]:オーディオをフルレングスの処理済み WAV にポイントします(既知の制限を参照)。複数のクリップ:クリップごとに 1 つの XML、その後 merge_xml.py output.xml "name" a.xml b.xml = 1 つのシーケンス、端から端まで
6b編集内容の再文字起こしエンドツーエンドチェック:audio.wav の保持された区間を連結し、Whisper で文字起こしし、カットポイントでテキストを読みます。他のチェックでは見逃されるもの(編集内に残った無音、3単語のための 8 秒のクリップ、切り取られた単語、生き残った失敗テイク)を捕捉します
7qc_repeat_scan.py決定的チェック:編集内に 30 秒以内に繰り返されている 5-gram が残っている場合、またはポーズまたはカットの後に続く 2 つの単語が編集の 8 秒未満前にすでに発言されていた場合(バリアントで繰り返されたテイク)は終了コード 2。すべてのヒットはスクリプトと耳(hear.py)でチェックされます:生き残ったリテイク(最後のものを保持)または意図的なレトリック(アナフォラ、列挙)
7bmontage_qc.py <work>編集のオーディオが文字起こしされ、クリップごとに読み取られます。Premiere の単語(P)と Whisper(W)を比較:1.6 秒以上のブランクまたは 1 秒未満のフラグメントがある場合は終了コード 2。疑わしいエッジは hear.py audio.wav 12.3-14.0 ...(分離されたスライスでの Whisper)でチェックされます
8report_v2.pyレポート:編集とクリップの長さ、テイク、疑義。--notes は「意図的に保持」と、スクリプトの機密部分に触れる箇所について

ステップ 3、判断ルール

ハードルール:

  • 繰り返しテキスト:最後のテイクを保持(たとえ以前のものよりも品質が低くても)
  • つまずき:最長の連続部分を保持
  • 疑義:flag、決して disable しない。過小カットは過剰カットよりも優れています。カットの追加は簡単ですが、欠落した箇所の復元は困難です。
  • カット境界は Premiere の単語にスナップし、保持される最初の単語のアタックの約 0.15 秒前に空気を残します。

実際の編集から学習したルール:

  • 2 つのテイクカットの間に挟まれた 2 秒未満の島は、必ず聴取されます(hear.py)。ほとんどの場合、言い間違いです。Premiere のテキストだけで判断しないでください。息継ぎが Premiere に単語として含まれる可能性があり、「ご視聴ありがとうございました」のような Whisper のハルシネーションは、実際には単語がまったくないことを意味します。
  • スクリプトの文ではないノイズを伴う無音(余談、「さあ始めよう」、カメラの操作)は、フラグではなくカットされます。
  • 文頭のフィラー的な冒頭部(言語ファイルの「openers」リスト、例:「So,」や「Well,」)はカットされます。
  • 文中の逐語的な吃音(「It's it's」)は無効化されます。ただし、句点を挟んで名前が繰り返される場合(「Nikon よりも文書化が不十分です。Nikon には豊富なドキュメントがあります」)は吃音ではありません。Premiere はそれをダブルとして書き込んでいる可能性があります。単語単位のカットの前には、必ず hear.py でスライスを聴取してください。
  • 孤立した接続詞(孤立した「And / So / But」)がカットサイレンスの直前にある場合は、カットに含めます。同様に、カットとポーズの間に挟まれ、別のアタックが続く孤立した言い間違いの単語も同様です。
  • Premiere のトランスクリプト内の、Whisper での対応物がない無意味な単語が冗長な余談の中にある場合、それはつまずきです。少なくともフラグを立ててください。
  • 情報を伝えず、次の文を繰り返すフィラー句:フラグのみ(編集者の判断です)。
  • 「リテイク」は前の文の終わりである可能性があります。Premiere によって日付が正しくない場合があります(5 秒にわたる単語)。編集の Whisper テキストがそれを示します。
  • Premiere は 1 つの文を 2 つに分割することがあります。2 単語の「言い間違い」は、次の文の始まりである可能性があります。
  • Premiere は小さな呟き言葉を見逃すことがあります。繰り返された文をカットすると、孤立したリードインが残ることがあります。最初に hear.py でスライスを聴取してください。takes.json のエントリの 6 番目の要素で手動で境界を設定します。
  • 単一の重複単語(「the the」):Premiere が両方を同じ息継ぎ内に日付するため、境界が前の単語を飲み込む可能性があります。結合部分(ffmpeg atrim で 2 つの保持部分を結合し、hear.py)を聴取してください。
  • 2 つのクリップの継ぎ目:クリップ 1 の終わりとクリップ 2 の始まりを一緒に聴取します。クリップ 1 の終わりに始まり、クリップ 2 の始まりで繰り返される文は、最初の単語からカットされます。
  • 編集者に向けてカメラに向かって話された指示(「これは君へのメッセージだ、ここにグラフィックを入れてくれ」)は指示としてカットされ、レポートに記載されます。イラストを入れる場所を示しているためです。
  • テイクをカットした後、保持されたテイクのアタックを聴取します(Premiere に 2 つの単語がある場合、最初の単語が食べられる可能性があります)。

Premiere トランスクリプトは .prproj 内にあります

.prproj は gzip 圧縮された XML で、ブロック <ExternallyProvidedTranscriptDocument><TranscriptData Encoding="base64"> を含み、そのペイロードは FlatBuffers バッファです。extract_prproj_transcript.py がそれをデコードします:

Segment -> f0 i64 start_ticks, f3 vector<Word>, f4 string language
Word    -> f0 i64 start_ticks, f1 i64 duration_ticks, f2 string text, f3 f32 confidence
Premiere ticks = 254016000000 per second

空のテキストを持つアイテムは、Premiere によってマークされたポーズです(その長さは無音全体をカバーします)。スクリプトはそれらを削除します。削除しないと、単語間のすべてのギャップが 0 になり、silence_cuts.py は何も見つけられません(症状:「gaps > 1s: 0」および単語が 39 秒間にわたる)。

1 つのプロジェクト内の複数のクリップ:.prproj はクリップごとに 1 つのトランスクリプトを保持します。--rush NAME.MOV は、クリップの長さに合うものを選択します(指定がない場合は最も長いものを選択し、警告を表示します)。最後の単語の開始位置を比較し、長さの 0.3% のドリフトマージンを持ちます。単語数がクリップ間で異なることを確認してください。クリップごとに 1 つのワークフォルダを作成し、その後 merge_xml.py を使用します。

このトランスクリプトにおける 2 つの落とし穴:

  1. ファイルに対してドリフトする可能性があります:ステップ 2b。カットはファイル時間で行われます(XML が読み取るもの)。したがって、単語が修正され、その逆はありません。
  2. 単語の長さが後続の無音を飲み込む可能性があります:無音は単語間に存在しなくなり、カットされなくなります。silence_cuts.py はこれらの単語を実際の終わりに戻します(trim_overflow)。Premiere の単語終了を決して信頼しないでください。開始位置のみが信頼できます。

さらなる落とし穴(無音内に日付された単語、ミュートフラグメント、小さな島):references/lessons.md

テイクカット境界:単語開始の最も近いエネルギー谷上で、保持される単語のアタックの前に 0.12 秒の空気を残します。カットは単語インデックスで記述し、秒数では記述しません。再調整後も存続します。

v1 パイプライン(下記)は、Premiere のトランスクリプトがない場合のフォールバックとして残ります(単語単位のリテイクはおそらく見逃されることを警告します)。

マシン要件

起動時にチェックされます。不足がある場合は、INSTALL.md(Whisper のみの場合は references/whisper-setup.md)を参照するように指示します。

brew install whisper-cpp ffmpeg
mkdir -p ~/Models/whisper
curl -L -o ~/Models/whisper/ggml-large-v3-turbo.bin \
  https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin

Python 3 with numpy(他には何も必要ありません)。API キーやアカウントは不要で、モデルダウンロード後にマシン外に出るデータはありません。

Pipeline v1(フォールバック、8 ステージ)

scripts/derush.py によって実行されます。各ステージはクリップの隣にある <clip>_Derush_vN_work/ に書き込み、削除されることはありません(再開と検査が可能です)。

#スクリプト役割
1derush.py(エントリポイント)ffprobe メタデータ、バージョン番号
2extract_audio.pyffmpeg で audio.wav 16 kHz モノラルを作成
3transcribe.pywhisper.cpp で transcript.json を作成
4mechanical_cuts.py言語ファイルの単語リストとパターンを使用して cuts_mechanical.json を作成
5意味解析(Claude)cuts_semantic.json へ(下記参照)
6merge_cuts.pyマージ、単語へのスナップ、スコアを cuts_final.json へ
7build_premiere_xml.py.xml(XMEML / FCP7)へ
8build_report.py.report.md へ

ステージ 5:意味解析

スクリプトは prompt_semantic.txt を書き込み、停止します。これが通常のルートです。スキルを実行している Claude は、その後以下を行います。

  1. prompt_semantic.txt をすべて読み込みます。
  2. プロンプトのルールに従ってトランスクリプトを分析します。
  3. JSON を cuts_semantic.json(パスはプロンプトで指定)に書き込みます。
  4. 再開:derush.py <clip> --resume-from=6 --work-dir=<work>

cuts_semantic.json がすでに存在する場合、このステージはスキップされます。

3 レベルの判断(スキルの哲学)

すべての提案されたカットには、0 から 1 の間の信頼度があります。

  • disable:その部分はタイムラインから削除され、非アクティブ化はされません。build_spine_clips() は減算によってシーケンスを構築します。保持された区間のみが残り、端から端まで配置され、シーケンスの長さは保持された区間の合計になります。これはすでに適用された「リップル削除」に相当します。しきい値:機械的カットは >= 0.85、意味カットは >= 0.92(LLM はしばしば境界を超過します)。
  • flag(0.6 ~ 0.85):カットは行いません。その部分はアクティブなクリップとして残り、適切な位置に赤いシーケンスマーカー(「DOUBT (conf X): reason」)が付きます。ユーザーが判断します。
  • ignore(< 0.6):何もしません。タイムラインをノイズで埋め尽くさないためです。

これらのセマンティクスを決して逆にしないでください。非アクティブ化されたグレー表示のクリップを手動で削除するように提供することは、ユーザーに作業を移すことであり、除去することではありません。このスキルの約束は、直接使用可能なシーケンスを提供することです。

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

関連スキル