analyze-video について
ButterCutで編集前に映像を分析し、文字起こし、コンタクトシート、クリップ要約を作成するスキルです。処理の進行管理や任意の文字起こし修正、素材内容の確認も扱います。
主な機能
- 01文字起こしとシート作成の手順
- 02映像シートに基づくクリップ要約
- 03任意の文字起こし修正
- 04進捗管理とエラー対応
活用シーン
- 01ラフカット前の動画ライブラリ準備
- 02クリップの内容や会話の確認
- 03ライブラリ情報に基づく文字起こし修正
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ barefootford/ buttercut --skill analyze-videoインストール後、Claude Code で/analyze-videoを入力して読み込まれたか確認します。
同梱ファイルagent_prompt.md
詳細
スキル:動画を分析する(親向け概要)
これは、メインスレッドで 動画を分析する ワークフローステップを実行するための手順書です。ライブラリのセットアップ後、カット作業を始める前に実行します。クリップごとに生成される3つの成果物、すなわち音声の transcript、contact_sheet、Markdown の summary を扱います。ラフカットエージェントは、必要に応じてトランスクリプト JSON に対して script_extractor.rb を実行し、台詞を読み込みます。別個のスクリプト成果物はありません。
SKILL.md は親のディスパッチ概要です。サブエージェントに渡すプロンプトは agent_prompt.md にあります。Task エージェントの起動時に、その内容をインラインで含めてください。SKILL.md は渡さないでください。
用語
- ユーザー向け表現: 「素材の分析」または「素材を分析する」と表現します。
- 内部/ファイル名: 「文字起こし」(
library.yamlのtranscriptフィールドなど)とします。
前提条件
- ライブラリのセットアップが完了していること(
library.yamlが存在し、スキーマが最新であること。そうでない場合は、AGENTS.md に記載されたマイグレーションを実行します)。 libraries/settings.yamlを直接読み込み、whisper_modelを確認します。ライブラリのフィールドについては、ruby lib/buttercut/library.rb <name> summaryでスナップショットを読み込み、JSON から必要な値を取得してください。library.yamlを直接解析しないでください。
この時点で、ライブラリの処理全体の計画を把握できるよう、ユーザーに見える形で、技術的でない大まかな手順の todo リストを作成してください。カフェイン関連の手順は、ユーザーが希望した場合のみ含めます。例:
- [ ] Keep computer awake
- [ ] Create transcripts (0/30)
- [ ] Analyze footage (0/30)
- [ ] Let computer sleep again
- [ ] Review the footage together
これらの公開 todo は、以下の手順に対応します。「コンピューターをスリープさせない」はステップ 1、「コンピューターを再びスリープ可能にする」はステップ 6 です。「文字起こしを作成する」は、ステップ 2 の機械的な実行と、任意のステップ 3 の調整作業を含みます(ステップ 2 の [transcript …] の進捗行を基準に件数を更新し、調整作業を行う場合はステップ 3 の間も進行中にしておきます)。「素材を分析する」はステップ 4 の要約作成を追跡します(コンタクトシートの作成後ではなく、クリップの要約ごとに件数を更新します)。「素材を一緒に確認する」はステップ 5 です。
公開チャットでは、これらの技術的でない手順を使って説明してください。技術的な作業(WhisperX、コンタクトシートの生成、Sonnet による要約)は内部で行います。
ステップ 1 — 処理中にスリープしないようにする
分析を始める前に、AskUserQuestion を使ってユーザーに次のように尋ねます。「処理にしばらく時間がかかる場合があります。完了するまでコンピューターがスリープしないようにしますか?」選択肢は「はい(推奨)」と「いいえ」です。
「はい」の場合は、プラットフォームのスリープ防止ヘルパーをバックグラウンドで起動し、PID を保存します。分析が終わったら、ステップ 6 で停止します。(バックアップは、このスキルの実行後に呼び出し元のスキル process-library が処理します。)
macOS:
caffeinate -i -w $$ &
KEEPAWAKE_PID=$!
Windows(Git Bash):
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/keep_awake.ps1 &
KEEPAWAKE_PID=$!
どちらも、素材の処理中にアイドル状態によるスリープを防ぎます(ディスプレイは消灯することがありますが、問題ありません)。
ステップ 2 — 映像素材を処理する(文字起こし、次にコンタクトシート)
(process-library を介さずにこのスキルに直接たどり着いた場合は、まずユーザーに「動画が [N] 本見つかりました(合計サイズ:[total size])。映像の分析を開始します……」と伝えてください。)
これは、機械的なコマンドを 2 つ続けて実行する手順です。まず文字起こしを行い、次にコンタクトシートを作成します。決して同時に実行しないでください。WhisperX は RAM を大量に使用するため、2 つを重ねて実行しないようにしています。どちらもサブエージェントを使って独自に作り直さないでください。毎回同じように実行され、1 回につき約 2 クリップを処理し、各クリップの完了と同時にその情報を library.yaml に記録します。どちらも冪等性があり、対象の成果物がまだないクリップだけを処理するため、再実行すれば未完了の分だけが処理されます。ミニチュアの Sidekiq のようなジョブサービスで実行されます。コマンドを実行した後、返されるログファイルを監視して進行状況を確認してください。
ステップ 2a — 文字起こし。 Claude Code を使用する場合は、Bash ツールで run_in_background: true を指定して実行してください。それ以外の場合は、バックグラウンドで実行するための適切なツール/引数を使ってください。
ruby lib/buttercut/process_footage.rb transcripts <library-name>
起動したらすぐに、ログファイルに対して Monitor または同等の仕組みを設定し、クリップが完了または失敗するたびに通知を受け取れるようにしてください。
tail -f tmp/logs/processing/<library-name>/$(date +%Y-%m-%d).log | grep --line-buffered -E "TranscribeJob (done|error)|transcript: [0-9]+/[0-9]+|Error|error:|failed|Traceback"
ruby lib/buttercut/library.rb <name> pending transcript # JSON list; done = N − its length
クリップの処理が進むたびに「文字起こしを作成 5/20」、つまり完了したクリップ数/クリップ総数を更新し、ユーザーが進行状況を確認できるようにしてください。バックグラウンドタスクが完了すると、いずれかのクリップが失敗していた場合はゼロ以外の終了コードで終了します。失敗した場合は 1 回再実行してください。再度失敗した場合は原因を調査し、適切に処理できるよう修正するか、クリップの問題についてユーザーに伝え、必要に応じてライブラリから除外してください。
2b を開始する前に、2a が完了するまで待ってください。
ステップ 2b — コンタクトシート。 文字起こしが完了したら、シートを作成します(ffmpeg による高速処理なので、フォアグラウンドで実行してかまいません)。
ruby lib/buttercut/process_footage.rb contact-sheets <library-name>
コンタクトシートは内部処理にとどめ、公開する件数には含めないでください。2a と、必要な調整(ステップ 3)が完了したら、「文字起こしを作成」を完了としてマークしてください。
調整(任意):どちらのステップも libraries/settings.yaml の parallel_jobs(デフォルトは 2)を読み込みます。1 回だけ値を変更するには、--jobs N を指定してください。それぞれ、後から確認できるように tmp/logs/processing/<library>/ の下にタイムスタンプ付きログを書き込みます。
再処理。 各ステップでは、成果物がすでにあるクリップはスキップされます。たとえば、名前を誤って聞き取った文字起こしをやり直すには、そのステップを --force --clips NAME.mov を指定して再実行してください。--force だけを指定すると、すべてのクリップが再構築されます。
ステップ 3 — 文字起こしを調整する(判断が必要な作業 — transcript_refinement: true の場合のみ)
文字起こしのうち、ライブラリのコンテキストを使って誤認識された固有名詞を修正する調整は、判断が必要な唯一の作業です。そのため、機械的な処理の後にモデルステップとして実行します。ライブラリの transcript_refinement が false の場合は、このステップ全体をスキップしてください。
true の場合は、ステップ 2a で書き出した文字起こしを対象に、調整用サブエージェントを 2~4 個並行して順次起動します。各サブエージェントのプロンプトには skills/transcribe-audio/refine_instructions.md をそのまま含め、次の項目をインラインで渡してください。
transcript_path—libraries/<library>/transcripts/にある、クリップの文字起こし JSON の絶対パスuser_contextとfootage_summary—ruby lib/buttercut/library.rb <name> summaryから取得した現在の値(空文字列でもかまいません。調整では、意味不明なトークンの修正や、本人による証言の修正も引き続き行います)
サブエージェントは文字起こし JSON を直接編集し、修正内容の短いリストを返します。library.yaml には触れません。ステップ 2a ですでに transcript フィールドが設定されています。調整が完了したら、公開用の「文字起こしを作成」ToDo を完了としてマークしてください。
ステップ 4 — 要約(Sonnet サブエージェント、バッチ処理、ローリング方式)
Sonnet モデルで analyze-video サブエージェントを実行します。Sonnet は Haiku よりもコンタクトシートをかなり具体的に読み取り、衣服、建築、カメラのフレーミングなどを捉えます。要約はその後のすべてのカット判断に使われるため、その価値があります。
サブエージェントごとにクリップを 10 本処理し、最大 10 個のサブエージェントをローリング方式で並列実行します。 各サブエージェントは担当する 10 本のクリップを順番に処理します。バッチ化することで、エージェントごとの実行にかかる約 5〜10 秒のオーバーヘッドを分散できます。93 本のクリップがあるライブラリなら、サブエージェントは合計約 10 個で済み、93 個にはなりません。1 つのサブエージェントから応答があり次第、次のサブエージェントを開始します。10 個すべての処理が終わるまで待つと、最も遅いエージェントに引きずられ、実時間の約 30%を無駄にします。
各サブエージェントには、クリップレコードを 10 件インラインで渡します。各クリップレコードには以下が必要です。
video_filename— 動画のベース名(要約のヘッダーと返信行に使用)duration— library.yaml の長さを表す文字列(例:00:01:19)。エージェントはこれを要約のヘッダーに記載しますcontact_sheet_path—_full.jpgの絶対パス(ステップ 2 で取得)transcript_path— 音声の文字起こし JSON の絶対パス(ステップ 2 で取得)。サブエージェントは必要に応じてscript_extractor.rbで会話内容を抽出しますsummary_output_path— エージェントが要約の Markdown を書き込む絶対パス。このファイル名を手作業で組み立てないでください。ライブラリに正規のパスを問い合わせます:ruby lib/buttercut/library.rb <name> field_path summary <clip>(ファイル拡張子の有無にかかわらず、summaries/summary_<clip>.mdの規則に従ったパスを取得できます)
サブエージェントからバッチが返るたびに、そのバッチ内の各クリップについて summary を指定して library.yaml を更新します。
ruby lib/buttercut/library.rb <name> complete summary <filename> [<filename>...]
contact_sheet フィールドはステップ 2 ですでに入力されているため、サブエージェントから返されるのは要約のみです。
サブエージェントが要約をディスクに書き込まず、インラインで返した場合(Sonnet が「Write ツールはブロックされています」と誤って判断し、Markdown を返信に出力することがあります)は、すぐに再実行しないでください。エージェントの応答から各要約を取り出し、親スレッドから対応する summary_output_path に Write してください。その後、通常どおり complete summary コマンドを実行します。再度ディスパッチするより速く、内容もすでに揃っています。
(長いクリップ用に生成されたセグメントごとのコンタクトシートは、ディスク上で _full シートと同じ場所にあり、規則に基づいて見つけられます。library.yaml には記載されません。)
要約が完了するまで先に進まないでください。クリップの要約ができたら「Analyze footage」の件数を進め、すべて完了したら完了としてマークします。
画像。 静止画像ではステップ 2〜3 を丸ごと省略します(文字起こしする音声も、作成するコンタクトシートもありません)。必要な成果物は summary のみで、動画と同様に ruby lib/buttercut/library.rb <name> pending summary に表示されます。見る対象そのものが画像なので、画像を直接要約します。メインスレッドまたは Sonnet サブエージェントから画像ファイル(サイズは小さいです)を読み込み、被写体、場面、構図、画像内のテキストなどを 3〜4 文で説明し、ruby lib/buttercut/library.rb <name> field_path summary <image-filename> で取得した正規のパスに書き込みます。画像クリップのキーには拡張子が含まれる点に注意してください(title-card.png → summaries/summary_title-card_png.md)。この変換は field_path が処理します。その後、同じ方法で記録します:ruby lib/buttercut/library.rb <name> complete summary <image-filename>。
Step 5 — 映像の内容をユーザーと確認する
(これは「映像を一緒に確認する」todoです。)すべての要約を書き終えたら、映像に実際に何が映っているかを話し合います。登場人物の名前、場所、物語の流れ、テーマから外れたクリップや関係のないクリップ、そしてこのライブラリに対するユーザーの創作意図を確認してください。通常の会話で進め、選択肢を明確に提示する場合に限り、AskUserQuestion を使ってください。確認できた内容に応じて、次を更新します。
footage_summaryとuser_contextは、ruby lib/buttercut/library.rb <name> update_metadata footage_summary "..."を使って更新します(user_contextについても同様です)。- 要約で人物を間違えて記載していたり、重要な詳細を見落としていたりする場合は、該当する
summary_*.mdファイルを更新します(例:「ベージュのジャケットを着た男性」→ユーザーの名前)。
この手順で、徹底的に内容を確認します。それ以降のラフカット計画では、ライブラリを再度詳しく質問することなく、ここで得られたコンテキストを引き継ぎます。
Step 6 — スリープ防止ヘルパーを停止する
Step 1 で起動した場合は、ここで停止してください(両方のプラットフォームで実行します)。
kill $KEEPAWAKE_PID 2>/dev/null
並列サブエージェントのパターン(参考)
Step 3 と 4 で使用します。
親エージェントの役割:
library.yamlとsettings.yamlを一度読み込み、サブエージェントに必要な値をすべて取得します。- 必要な値をすべてプロンプト内に直接含めて、Task エージェントを起動します。
- エージェントの処理が完了したら、
LibraryAPI を使用してlibrary.yamlを順番に更新します(AGENTS.md を参照)。 - エラーと再試行に対応します。
子エージェントの役割:
- 親から直接渡された入力だけを使用して、割り当てられたクリップを処理します。
- トランスクリプト JSON をその場で調整する(refinement)、または事前生成されたコンタクトシートを読み込み、
script_extractor.rbを通じてトランスクリプトから会話を抽出し、1 回の Write 呼び出しで要約の Markdown を書き込む(analyze-video)。(WhisperX はサブエージェントではなくなりました。Step 2a でprocess_footage.rb transcriptsが実行します。) - ファイルパスを含む、簡潔で構造化された応答を返します。
各スキルの agent_prompt.md には、そのスキル固有の IO 契約が記載されています。これには、サブエージェントが library.yaml を読み込むか、書き込むかも含まれます。(先にお伝えすると、サブエージェントが library.yaml に書き込むことはありません。Library API を通じて書き込むのは、親エージェントだけです。)
分析の完了前にユーザーがラフカットを希望した場合
「今すぐラフカットを作成できますが、映像をすべて分析してからのほうが、よりよいものを作成できます。このまま進めますか?」と警告します。ユーザーが確認した場合は、そのまま進めます。そうでない場合は、分析が完了するまで待ちます。