Communitygithub.com

omniharmonic/agentic-video-editor

アセンブリカットをラフカットに仕上げます。無音時間、フィラーワード(えー、あのー)、繰り返しや言い間違いを除去し、すべてのカットをカメラ切り替え、カットアウェイ、またはズームインで隠します。人間がアセンブリ編集を承認した後、キャプション、音楽、または最終カットの前に使用します。ユーザーが「きれいにして」「詰めて」「えーを消して」「無音をカットして」と言ったときにも使います。

agentic-video-editor とは?

このスキルは、動画編集パイプラインにおいてアセンブリ編集(assembly cut)をラフカット(rough cut)へと変換します。人間の編集者がアセンブリ編集を承認した後、キャプションや音楽の追加、最終カットの前に実行することを想定しています。主な機能として、無音時間(ポーズ)の短縮、フィラーワード(「えー」「あのー」など)の除去、言葉の繰り返しや言い間違いの削除を行います。すべてのカットは、カメラの切り替え、カットアウェイ(別カメラへの切り替え)、またはパンチイン(ズームイン)で視覚的に隠されるため、視聴者に違和感を与えません。DaVinci ResolveのスクリプトAPIを介して動作し、既存のアセンブリ編集を読み取り、新しいラフカットファイルを出力します。ポリシーはYAMLファイルで設定可能で、ツール自体を変更することなく編集の精度やアグレッシブさを調整できます。また、ドライランによる事前確認、詳細な説明出力、手動オーバーライド機能も備えており、編集者による判断を支援します。

対応~Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/omniharmonic/agentic-video-editor/tree/HEAD/skills/ave-cleanup

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

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

ドキュメント

クリーンアップ:アセンブリ → ラフカット

edits/assembly.vN.json、work/transcript.json、および分析用音声(work/audio/*.16k.wav)が必要です。生のフッテージや既存の編集を編集することはありません。各実行は同じアセンブリから次の edits/rough.vN.json を書き出すため、ポリシーを変更した後に再実行しても安全です。

1. ポリシーを確認し、ドライランを実行

ポリシー(config/cleanup.default.yaml、または <ep>/policy/cleanup.yaml、または --policy)にはすべての数値が保持されています。ポーズの長さ(pause.max_ms)、短縮後の長さ(target_ms、決して floor_ms を下回らない)、フィラーワード、保護対象などです。好み(「どのくらい詰める?」)について人間に確認し、コードではなくYAMLを変更してください。部分的なファイルでも問題ありません。デフォルト設定にマージされます。

ave cleanup <episode> --dry-run          # すべてを決定し、何も保存しない;標準出力はJSON
ave cleanup <episode>                    # edits/rough.vN.json + work/cleanup.json を書き出す
ave cleanup explain <episode>            # すべての判断を言葉で説明、人間の確認が必要な項目を表示
ave cleanup <episode> --name s1         # マルチセッションエピソード:assembly.s1 -> rough.s1 + work/cleanup.s1.json (説明も --name s1 で)。そのセッションの発話のみが判断される

2. 結果を評価する(そのまま進めないこと)

ave cleanup explain を読んでください。各項目を確認します:

  • totals:削除された時間が妥当か(通常、会話の3-10%)。非常に大きな数値はポリシーが過剰にアグレッシブであることを意味します。
  • 各 needs_review アイテム:review_phrase(「つまり」「なんか」などのクラスター)や flag アイテムは絶対に自動でカットされません。人間と判断してください。nonlexical =トランスクリプトが無音と認識したギャップ内の音(息、咳、見逃された「えー」)。カットする前にその時間を聞いてください。
  • mask: none のカットはオーディオクロスフェードのみで、目に見えるジャンプがあります。人間に伝えるか、ポリシーで修正してください(punch_in を許可する、カバレッジを追加する)。
  • 低い confidence(<0.6 は自動フラグ付き)は、通常、カット付近に静かなスポットが見つからなかったか(snap.valley: false)、ASRの単語が不確かだったことを意味します。
  • protect として保持されたポーズ(笑い声や「!」の後、「結局」の前):本当に間であることを確認してください。

独自の判断(ヒューリスティックが見逃した言い間違い、保持するフィラーワード)を追加するには、work/cleanup_overrides.json を書き込んで再実行します:

{"cut":  [{"words": [212, 214], "type": "false_start", "reason": "restarts the sentence", "confidence": 0.8}],
 "keep": [{"id": "c007", "reason": "intentional hesitation"}, {"e0": 431.2, "e1": 433.0, "reason": "keep this pause"}]}

words は work/transcript.json の words 配列のインデックスです。時間は単語全体にスナップされるため、オーバーライドで単語の途中をカットすることはできません。出力の warnings を確認してください。適用されなかったオーバーライドはここに報告されます。

3. カットの仕組み(説明できるようになるため)

カットは常に単語と単語の間(または削除された単語の正確な位置)でのみ行われ、その後 snap.window_ms 内で最も静かなスポットにスライドし、ゼロクロス点に合わせられます。オーディオクロスフェード:発話内で5-15 ms、保持されたポーズをまたぐ場合は20-40 ms。各スプライスのマスキング順序:カメラがすでに変更されている(話者変更)→ 別のカメラにカットアウェイ(そのカメラに映像があり、ショットが最低 min_hold_s 以上表示されている場合)→ ワイドショット → パンチイン(1.10-1.20倍、パンチインは1つだけ保持、3aを参照)→ クロスフェードのみ + needs_review。

3a. ズーム状態:1つのパンチイン、実際のホールド時間、そしてアウト(イン→アウト→インはしない)

数秒以内にIN、OUT、INが発生するパンチインは、落ち着きがないように見えます(最初の実際の最終カットに関するクリエイターフィードバック:42のズーム変更間隔のうち19が8秒未満、うち4つはイン・アウト・インのパターン)。ゆっくりとしたイン/アウトは自然です。そのため、すべてのパンチイン生成処理(上記のマスク、ペーシングパス、ショート動画のジャンプカットマスク)は、1つのルールを共有します(src/ave/zoomstate.py、キーは masks.zoom_min_dwell_s と pacing.zoom_min_dwell_s、デフォルト8秒、および max_ins_per_shot: 1。0でオフ):

  • カメラ上のズーム変更は、そのカメラでの前回のズーム変更から最低ホールド時間が経過していなければなりません(別のカメラへのカットアウェイはタイマーをリセットしません)。
  • ショットは1段階を超えてパンチインされることはなく、その後必ず戻ります。
  • ペーシングパンチインは、ホールドの最後まで(次の実際のカメラ変更まで)保持される持続的なリフレームであり、2〜4秒の一瞬ではありません。max_hold_s より長いホールドでは、文の区切りでホールド時間以上経過した後に戻ります。
  • マスクがこのルールを破る場合、カットアウェイ/他カメラのマスクが以前と同様に試みられます。どれも適合しない場合、カットは単純なオーディオクロスフェードと needs_review のマークが付けられ、判断の reason に punch-in blocked by the zoom limit: zoom on A2 already changed (in, ...) 0.8s ago と表示されます。これらは目に見えるジャンプカットです。確認してください(カット間隔が1.2秒未満の場所に集中します)。

ave cleanup は zoom_check(explain では Zoom:)を出力し、ave final は checks.zoom を出力します。どちらも short_dwell、in_out_in、multiple_ins を警告としてリストします(バリデーターは編集しません)。クリエイターがより多くのパンチインを望む場合、ホールド時間を耳で調整してください(masks: {zoom_min_dwell_s: 5})。ルールをオフにして13個のマスクされていないカットを「修正」しようとしないでください。代わりにカバレッジ(ワイドショットまたは他カメラ)を追加してください。

3a2. 単語内のカット(ポストパスチェックとテールパッド)

src/ave/cutwords.py はすべてのダイアログスプライスを editdoc.src_time でソースクロックに変換し、以下を報告します:(1) トランスクリプトの単語内に収まるカット(start + word_margin_s < t < end - margin。保持された単語をスライスする sliced、削除された単語の短い残骸を示す stub)、および (2) hot_edges:ASRの単語境界にあり、パッドがなく、音声が hot_db_below_speech 以内でスピーチレベルにあるカット。つまり、スパンテストは通過するが単語がおそらくクリップされていることを示します。Parakeetの単語時間は80 msグリッド上にあります(実際のエピソードのすべての単語)。したがって、境界の精度は±40 ms程度であり、ASRの単語終了は早めに設定されます。単語の31%で、エネルギーはASR終了から80 ms以上継続していました。そのため、カットは最大 pause.word_tail_pad_ms / word_lead_pad_ms(80 ms。低信頼度の「ゴースト」単語では150 ms)だけ削除された単語内にスライドすることがあります。ただし、それはスムーズな減衰に沿って実際の谷に到達する場合に限り、決して信頼できる実際の単語を通過することはありません。警告は cut inside a word: ... / cut at a word edge with speech continuing: ... listen, the word may be clipped と表示されます。承認する前に、それぞれの出力時間で聞いてください。ave final はコンパイルされた編集に対しても同じチェックを実行します(checks.word_cuts)。

3b. ペーシング:長いホールドの分割(マスク後)

マスクはカットポイントでのみ機能するため、長いターンは1分間同じカメラにとどまる可能性があります。マスキング後、ペーシングパスは pacing.max_hold_s(14)より長いすべてのホールドに2〜4秒のリアクションショットを挿入します。最初に role: wide カメラ、次にリスナーのカメラ(話している間は不可)、最後にパンチイン(1.10/1.20倍を交互)を試みます。単語の間でのみカットし、できれば強い文の終わりで、隣接するカットから少なくとも2.5秒離し、ダイアログには決して触れません。それぞれは reason: "pacing: reaction" と confidence を持つビデオセグメントです。

ave cleanup <episode> --no-pacing        # リアクションショットなしの同じラフカット、比較用
ave cleanup explain <episode>            # "Pacing:" 行:リアクションの種類別の数、制限超過ホールドの前後、平均ショット長、1分あたりのカット数

Pacing: 行と work/cleanup.json の pacing から判断します(そのまま進めないでください):

  • holds_over_limit は0に近づくべきです。STILL OVER THE LIMIT の行はその理由を示します:1分あたりのカット数上限(max_cuts_per_min、デフォルト8)に既に多くのマスクが存在する、単語境界がない(非常に長いASR単語)、またはリスナーカメラに映像がない。
  • cuts_per_min は上昇する可能性があります。実際の会話ではカットアウェイマスクだけで1分間に10〜12回になることがあり、max_hold_s + reaction.max_s を超えるホールドはとにかく修正されます(rate_override: true)。編集が忙しすぎると感じる場合、調整のレバーは pacing.* と同様に masks.*(カットアウェイ長、min_hold_s)です。
  • ave render またはResolveで3つのリアクションを見てください。リスナーは実際に反応していますか(話の中途ではない、話していない)?パンチインは弱い代替手段です。3台目の(ワイド)カメラがあるとペーシングははるかに良くなります。
  • クリエイターと耳で調整し、<episode>/policy/cleanup.yaml で設定します(2行で十分):pacing: {max_hold_s: 18} で落ち着いた感じに、{max_hold_s: 10} で忙しい感じに、hard_rate_cap: true で max_cuts_per_min を超えないように、camera_order: [listener, punch_in] でワイドをスキップ、enabled: false でオフ。完全なキーリスト:docs/cleanup-policy.md(「Pacing」)。

3c. ルームトーン(ギャップ用)

すべてのラフカットは自動的に tracks.room_tone を取得します。これは、ダイアログソースの分析用音声(チャンネル別マスターの場合はL+R合計、デッドチャンネルファイルの場合はライブチャンネル)から、編集で使用されるスパンの近くで検索された、最も静かで安定した2〜4秒の範囲です。発話、トランジェント、無音のレコーダーパッドは除外されます。エピソード時間で {"src","e0","e1","rms_db","auto":true} として書き込まれます。ポリシーキー:config/cleanup.default.yaml の room_tone:(enabled、min_s、max_s、steady_db、min_floor_db、margin_s)。クリーンアップの警告「no room tone」は、適切な範囲が存在しないことを意味します。手動で tracks.room_tone を設定し、ave clips build --force を実行すると、ギャップが生成されるようになります。コンパイラが fill: room_tone のギャップをレンダリングするとき、フィルを両側で測定されたノイズフロアに合わせるため、レベルジャンプは発生しません。1つのギャップを耳で確認してください。

4. チェックポイント

ここで一旦停止します。人間向けに要約してください:前後の時間、件数(フィラーワード、繰り返し、言い間違い、ポーズ)、使用されたマスク、ペーシングの数値(挿入されたリアクション数、前後のホールド数、1分あたりのカット数)、タイムスタンプ付きのすべての needs_review アイテム、およびすべての warnings(long hold や STILL OVER THE LIMIT のペーシング行を含みます)。彼らがラフカットを承認するまで、キャプション、音楽、または最終カットを開始しないでください(ave status で待機状態として表示されます)。プレビューのレンダリングには ave render(別のステージ)が必要です。

障害モード

  • Missing analysis audio:ave audio <episode> を実行してください。No assembly edit:ave assemble <episode> を実行してください。
  • policy pause: need 0 < floor_ms <= target_ms <= max_ms:YAMLを修正してください。メッセージはキーを指定します。
  • すべてがフラグされた / 何もカットされない:トランスクリプトにフィラーワードが含まれていない可能性があります(一部のASRエンジンはそれらを削除します)。work/transcript.json で「えー」を確認してください。ない場合、クリーンアップはそれらを認識できません。--asr whisper での再トランスクリプションを試すか、nonlexical 検出に依存してください。
  • 長いファイルでタイムスタンプがずれる(カットが遅れて配置される):ave sync を再実行してください。単語の時間はトランスクリプトの精度に依存します。

Individual skills in this repo

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

関連スキル