mcpField
A
anibon-timestamper-local

anibon-timestamper-local

github.com/zeniththクリエイティブ・メディア172 回インストール今日更新
リポジトリ

anibon-timestamper-local について

長時間の YouTube ライブ配信からタイムスタンプとテーマ別要約を作るローカル処理スキルです。再帰型またはグループ型の分割処理に、文字起こしの整形、ローカルのマルチモーダル分析、検証工程を組み合わせます。

主な機能

  1. 01再帰型とグループ型の処理モード
  2. 02文字起こしの整形とエンティティ用語集の生成
  3. 03ローカルのテキスト・ビジョンモデル分析
  4. 04テーマ別のタイムスタンプ整理
  5. 05タイムスタンプの監査と整形

活用シーン

  1. 01長時間配信のチャプター用タイムスタンプ作成
  2. 02ローカルモデルによる配信の要約
  3. 03映像フレームや資料を使った曖昧な話題の確認
  4. 04公開前の文字起こし誤りの正規化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zenithth/anibon-stream-synthesis --skill anibon-timestamper-local

インストール後、Claude Code で/anibon-timestamper-localを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

config.json
references/
timestamper-handoff.md
scripts/
launch_local.bat
launch_local.ps1
launch_local.sh
launch_local.zsh
prepare_video.py
process_chunks_local.py
signal_detector.py
scripts/anibon/
__init__.py
config.py
domain_db.py
knowledge_reader.py
lmstudio.py
multimodal.py
parity_gates.py
phonetic_bridge.py
prompts.py
state.py
summarizer.py
timestamps.py
topic_scanner.py
transcript_source.py
vision_verify.py
world_sanitizer.py
tests/
__init__.py
test_config.py
test_domain_db.py
test_knowledge_reader.py
test_lmstudio.py

詳細

Anibon Timestamper(ローカル P100 エディション)

概要

Dynamic Recursive Rolling Summary ステートマシン(--mode recursive)またはグループバッチ処理(--mode group)、マルチモーダルコンテキストの統合、自動タグ正規化、YouTube コメントの 2 パス整形により、長時間のライブ配信から YouTube のタイムスタンプと要約を生成するローカル処理パイプラインです。

使用する場面

  • クラウド API の費用をかけずに、単一 GPU(例:NVIDIA Tesla P100 16GB、Apple Silicon Metal、LM Studio、Ollama)でライブ配信をローカル処理する場合。
  • クラウド/最先端モデルの場合:クラウド API を利用でき、高並列のサブエージェントオーケストレーション(Claude 3.5 Sonnet、Gemini 2.0 Pro)を希望する場合は、代わりに anibon-timestamper を使用してください。

関連スキルと必須のサブスキル

  • anibon-world-identity(必須):配信でゲーム、アニメ、Pokémon、特撮、ポップカルチャーを扱う場合は、必ず読み込む必要があります。タイムスタンプを確定する前に、エージェントはローカルの参照資料(references/INDEX.md、atlas_fgo.db、pokemon.db、garbled_replacements.json)を照合し、キャラクター名、ゲームタイトル、用語を確認する必要があります。
  • whisper-corruption-recovery:Whisper の文字起こしに繰り返しループや無音の途切れが含まれている場合、自動的に呼び出されます。
  • anibon-local-transcription:YouTube に字幕や自動生成字幕がない場合に使用し、16kHz 音声を抽出してローカル GPU で whisper.cpp を実行します。

パイプラインアーキテクチャ

| 0. ノイズ除去と事前正規化 | signal_detector.py / anibon/(自動) | garbled_replacements.json + default_mappings.json | チャンクの読み込み/シグナル検出前に、ASR の話者マーカー(>>)、効果音タグ([เพลง]、[Applause])、音楽記号(♪)、繰り返しの途切れループを除去し、音声上のずれを修正します。 | | 0.5 ナレッジの自己読み込み | anibon/knowledge_reader.py(自動) | signals.json + references/*.md + DBs → entity_glossary.json | シグナルに一致する分野別の Markdown 参照資料を自動で読み込み、ローカルの SQLite データベース(atlas_fgo.db、pokemon.db)を検索して、チャンクごとに絞り込んだ検証済みエンティティ用語集を作成します。--no-knowledge-reader で無効にできます。 | | 1. 準備とチャンク分割 | prepare_video.py | YouTube URL → raw_transcript.json、chunks/*.txt | 字幕をダウンロードし、音声/文字起こしを重複するチャンクに分割します。 | | 1.5 LiveChat とムード検出 | anibon/parity_gates.py(analyze_555.py) | livechat/ → mood_555.json | 555/笑いの集中箇所を自動検出し、チャンクのムード/トーン(*_PULSE、HOT、WARM、QUIET)を分類して、プロンプトのトーン設定に反映します。 | | 2. トピックの分割(パス 1) | process_chunks_local.py | chunks/、signals.json、ストーリーボードのキーフレーム(--multimodal-chunks) | ローカル LLM/VLM を使用し、映像によるグラウンドトゥルースとムードのトーンヒントを参考に、話題の変化/継続を検出してタイムスタンプを出力します。 | | 2.5 視覚的なグラウンドトゥルース(オプション) | anibon/vision_verify.py(--vision-verify) | video_360p.mp4 + 曖昧なスタンプ | パス 2 の組み立て前に、ローカルのビジョンモデルで画面上の映像フレームを確認し、曖昧な固有名詞や [?] タグを検証します。 | | 3. 要約と組み立て(パス 2) | anibon/summarizer.py(自動) | all_timestamps.txt → anibon_timestamps.md | タイムスタンプを、まとまりのあるマクロテーマ別のパート(通常 4~6 パート)に分類し、切り替わりの合図に合わせて調整します(find_best_boundary)。 | | 4. 聞き取れない箇所の収集と Whisper によるグラウンドトゥルース | whisper_dispatcher.py(パス後に自動実行) | garbled_notes_raw/ → garbled_notes.json → garbled_replacements.json | 要約後に自動実行されます。音声をその場で切り出し、ローカルの whisper.cpp で音声上のグラウンドトゥルースを文字起こしして、共有辞書を自動的に拡充します。 | | 5. 決定論的なパリティゲート | anibon/parity_gates.py(パス後に自動実行) | all_timestamps.txt、anibon_timestamps.md | 最前段のパリティチェックを実行します。audit_gaps.py は 10 分を超える欠落がないことを強制し、check_sections.py はバイトサイズと ASR の文字化けパターンを監査します(レポートのみ)。 |

モジュール式ライブラリアーキテクチャ(scripts/anibon/)
  • anibon/multimodal.py:ストーリーボードスライドの展開、適応型シーン変化・評価バッチ対応のキーフレーム選択(チャンクごとに1~16フレーム、16×9のRGBサイドカーキャッシュ、タイ語の指示表現の手がかりの固定)、OpenAI互換の複数画像ペイロードの構築、VLMの実行を行います。
  • anibon/knowledge_reader.py:signals.json からのドメイン知識の自動検出、正規表現による表・箇条書きのエンティティ解析、SQLite DBの拡充(atlas_fgo.db、pokemon.db)、entity_glossary.json の生成を行います。
  • anibon/timestamps.py:タグの正規化(TAG_REMAP)、タイムスタンプ行のサニタイズ、衝突防止(間隔を $\ge 45\text{s}$ に維持)、ウィンドウの検証を行います。
  • anibon/lmstudio.py:LM StudioおよびOpenAI互換クライアント(TokenMe、vLLM、Ollama)、モデルの解決(デフォルトは gemma-4-12b-it-qat@q4_k_xl または unsloth/gemma-4-26b-a4b-it@q2_k_x)、テキスト補完、Bearer認証、Cloudflareのバイパス、マルチモーダルVision API(Gemma 4 VisionおよびQwen-VL向けの image_url データURI)を提供します。
  • anibon/websearch.py:エンティティを無料で検証するための、ローカルJSONキャッシュ(websearch_cache.json)付きの軽量なDuckDuckGo検索を行います。
  • anibon/prompts.py:再帰的なローリング要約とグループバッチ処理のプロンプト、World Identity参照情報の挿入、検索・ビジョン用のコンテキストブロックを提供します。
  • anibon/summarizer.py:意味的・時系列的な重複排除と、マクロテーマ別のパート構成(通常4~6パート)を備えた、Pass 2のローカル要約機能です。
  • anibon/state.py:チェックポイントの永続化(anibon_timestamper_state.json)、チャンクの検出、マルチモーダルローダー(LiveChat、555 mood、activity)を行います。
多層型ハルシネーション防止・検証アーキテクチャ(4層防御)

ローカルの小規模LLM(例:12B~27B)は、最先端モデルが持つ膨大なパラメトリックな世界知識を持たないため、音声をもとにした推測や、英語タイトルのハルシネーションが起きやすくなります。anibon-timestamper-local は、決定論的な4層の防御パイプラインを実装しています。

  1. レイヤー1:メタデータとタイトルシグナルの取り込み(signal_detector.py)

    • extract_metadata_signals() を通じて、info.json から動画のタイトル、説明、タグを取り込みます。
    • discover_reference_games() を通じて、anibon-world-identity/references/*.md 内の参照用Markdownゲームを動的にすべて検出します。
    • 推論の前に配信のコンテキストを確立し、特定のゲームを一般的なカテゴリと誤認するのを防ぎます。
  2. レイヤー2:推論前のバッファー正規化とクリーニング(state.py)

    • load_chunk_file() によるチャンク読み込み中に、ASRによる話者名の揺れ(ปู่บอท、ลุงบอท、ปู่โบต → ปู่โบ๊ต)を自動的に修正します。
    • テキストをLLMプロンプトに渡す前に、default_mappings.json の音声対応表を適用します。
  3. レイヤー3:推測防止と不変のプロンプト指示(prompts.py)

    • STREAMER IDENTITY の不変条件を強制します:配信者は 'ปู่โบ๊ต' (Boat) のみです。'ปู่บอท'、'ลุงบอท'、'ปู่โบต' と表記しないでください。
    • ANTI-GUESSING CONSTRAINT を強制します:タイ語の音訳語を新たな英語表記に独断で翻訳しないでください。VERIFIED DOMAIN ENTITIES に見つからない場合は、タイ語の音訳表記を使うか、タイ語で動作を説明してください。新たな英語の固有名詞を作り出さないでください。
    • POKÉMON NAMING RULE を強制します:ポケモンのエンティティは、必ず 'タイ語名 (English Name)'(タイのコミュニティ名または公式名に続けて、括弧内に英語名を記載)の形式に従います。
  4. レイヤー4:Stage 5の決定論的な自動サニタイズ(process_chunks_local.py)

    • Pass 2の要約を構成する際に、sanitize_and_audit_timestamps() を自動的に実行します。
    • 残存する話者名の誤記や正規辞書のパターン(garbled_replacements.json、例:Archen → Arcane、Victor → Viktor)を決定論的に修正します。
    • タイムスタンプ行の大文字始まりの未検証ラテン語を、許可リストのタグや用語集と照合して監査し、疑わしいハルシネーションに対して決定論的な監査警告を出します。

実行モード

モード 1:再帰的ローリングサマリー(--mode recursive、デフォルトかつ推奨)

Pu Boatの配信では、時間の区切りではなく、自然な流れに沿って話題が展開します。話題の長さは3分の場合もあれば、25分に及ぶ場合もあります。

  • SAME_TOPIC:チャンク $N$ が進行中の話題を続ける場合、タイムスタンプを出力せず(タイムスタンプ0件)、ローリングサマリーに統合します。
    • 長尺トーク/ニュースの例外:独白や社会的な議論が複数のチャンクにわたって続く場合(タイムスタンプなしで8~10分超)、長い空白を残すのではなく、独立した別の切り口や具体的な政策批判を必ず抽出します(タイムスタンプ1件)。
    • 連鎖長の上限なしのサマリー不変条件:build_recursive_prompt() と状態の永続化(anibon_timestamper_state.json、recursive_outputs/chunk_XX.json)では、ハードコードされた文字数制限による切り詰めを行わず、rolling_summary と chunk_summary の全文を渡す必要があります。これにより、複数チャンクにまたがる話題の文脈が失われることを防ぎます。
  • TOPIC_SHIFT/ハイライト:話題が変わったら、それまでの文脈をフラッシュして切り替わりにタイムスタンプを付けます。デフォルトでは1件、チャンクあたり最大2件を出力します(各タイムスタンプの間隔は$\ge$45秒)。
  • テーマ別パート分け:Pass 2の要約器は、find_best_boundary を使ってパートの境界を配信者の切り替え合図(例:สรุป... และเตรียมเปลี่ยนไปคุย、เตรียมเริ่มเล่นเกม)に合わせながら、タイムスタンプを包括的なテーマ別カテゴリーに分類し、連番の整数パート(ส่วนที่ 1, 2, 3...)にまとめます(通常、全体で4~6パート)。10~18個の細かなパートへの過剰な分割は禁止です。まとまりのある話題の議論(シリーズ全体のレビューやゲームセッションなど)は、視聴者が見やすいように1つのパートにまとめます。同じゲームの連続プレイは10分以内にまとめ、トーク/ニュースのサブトピックには4分のウィンドウを使用します。
モード 2:固定ウィンドウグループ(--mode group、代替)

4つのチャンク(約16~20分)を1グループにまとめ、時系列のループブレーカーと衝突ガードを適用します。


コアパイプラインとクイックリファレンス

クイックコマンド
0. ノイズ除去と前処理(自動)

シグナル検出やLLM分析を行う前に、clean_transcript_noise() がASRのアーティファクト(>>、[เพลง]、♪、文字の繰り返し)を自動的にクリーンアップし、garbled_replacements.json と default_mappings.json にある2,000件以上のWhisperの正解データを適用します。手動で実行する必要はありません。

0.5 ナレッジの自動読み込みとエンティティ用語集(ステージ0.5、自動)

チャンクを処理する前に、run_knowledge_discovery() が signals.json を調べ、anibon-world-identity/references/*.md 内の一致するMarkdown参照を読み込み、ローカルデータベース(atlas_fgo.db、pokemon.db)を照会し、<workspace>/entity_glossary.json を出力します。チャンクのプロンプトでは、関連するエンティティが自動的に絞り込まれ(約300トークンを上限とします)、プロンプトのコンテキストに追加されます。

  • エンティティ用語集の検出をスキップするには、--no-knowledge-reader を渡します。
1. ダウンロードとチャンク分割(chunks/chunk_00.txt が存在する場合はスキップ)

macOS / Linux:

python3 scripts/prepare_video.py "https://www.youtube.com/watch?v=<VIDEO_ID>" \
    --workspace "~/youtube_<VIDEO_ID>_workspace" \
    --format txt --block 300 --overlap 30

Windows(PowerShell / Command Prompt):

python scripts\prepare_video.py "https://www.youtube.com/watch?v=<VIDEO_ID>" --workspace "$HOME\youtube_<VIDEO_ID>_workspace" --format txt --block 300 --overlap 30
2. タイムスタンプ処理を直接実行(フォアグラウンド)

macOS / Linux:

python3 -X utf8 scripts/process_chunks_local.py "~/youtube_<VIDEO_ID>_workspace" \
    --mode recursive --lang th

Windows(PowerShell):

python -X utf8 scripts\process_chunks_local.py "$HOME\youtube_<VIDEO_ID>_workspace" --mode recursive --lang th

ヒント

コメント1件あたりのバイト数制限(--byte-cap): YouTubeにコメントを1件ずつ貼り付ける際、各パートを厳密に3,500バイト未満にする必要がある場合は、--byte-cap を渡してください。デフォルトでは、まとまりのある大きなテーマごとのグループ分け(4~6パート)を維持するため、バイト数制限は無効です。

2.1 パイプライン内の画像による検証(任意)

Pass 2の要約を行う前に、ローカルの画像認識モデルを使って、曖昧または漠然としたタイムスタンプ(指示代名詞、ゲーム名の欠落、[?] マーカーなど)に対応する画面上の動画フレームを確認します。

python -X utf8 scripts\process_chunks_local.py "$HOME\youtube_<VIDEO_ID>_workspace" --mode recursive --lang th --vision-verify
2.2 ストーリーボードのキーフレームを用いたマルチモーダルチャンク分析(デフォルト:有効)

パス 1 では、トランスクリプトのテキストとともに、チャンクごとの高解像度ストーリーボードのキーフレームを VLM(Gemma 4 12B Vision、Qwen-VL など)に直接サンプルとして入力します。config.json("multimodal_chunks": true)でデフォルトで有効になっています。ゲームタイトルの誤帰属をなくし、イベントやチャプターの字幕をリアルタイムで根拠づけます:

# Enabled by default (Adaptive Scene-Change Mode):
python3 scripts/process_chunks_local.py ~/youtube_<VIDEO_ID>_workspace --mode recursive --lang th

# To tune visual sensitivity or evaluation batch size:
python3 scripts/process_chunks_local.py ~/youtube_<VIDEO_ID>_workspace \
  --eval-batch-size 8192 \
  --max-chunk-frames 16 \
  --scene-delta-threshold 0.06

# To disable adaptive scene deduplication (fallback to legacy fixed 3-5 frames):
python3 scripts/process_chunks_local.py ~/youtube_<VIDEO_ID>_workspace --no-scene-dedup

# To disable all multimodal analysis and run in text-only mode:
python3 scripts/process_chunks_local.py ~/youtube_<VIDEO_ID>_workspace --no-multimodal

適応型シーン変化キーフレームセレクター(scene_dedup=True):

  • 静止画面:動きのないトーキングヘッドや待機画面を 1~2 フレームに減らし、物理バッチの計算量とプロンプトトークンを節約します。
  • 動的なアクション:視覚的なシーン遷移が発生すると、--eval-batch-size(デフォルトは 8192)を上限として、5 分のチャンクあたり最大 16 フレームまで自動的に増やします。
  • タイ語の直示表現のピン留め:Pu Boat が直示表現("ดูอันนี้"、"ในจอ"、"ตรงนี้"、"[?]")を使うたびに、該当する正確な映像フレームをピン留めします。
  • RGB サイドカーキャッシュ:16×9 の 432 バイトのダウンサンプリング済みバッファー(tile_XXXXXX.rgb)を .jpg タイルとともに自動的に保存し、比較や再実行の際に ffmpeg のサブプロセスを繰り返し起動するオーバーヘッドをなくします。
  • クリーンスレートの --no-resume:--no-resume を渡すと、古い recursive_outputs/chunk_*.json ファイルが自動的に削除され、前回のチャンクが残って混入することなく、クリーンな状態で実行できます。

以前の結果を保持したまま既存のワークスペースを再実行する場合(例:テキストのみからマルチモーダルへの切り替え):

cd ~/youtube_<VIDEO_ID>_workspace
cp -a . ~/youtube_<VIDEO_ID>_workspace_text_backup
cp anibon_timestamps.md anibon_timestamps_text_only.md
cp all_timestamps.txt all_timestamps_text_only.txt
mv recursive_outputs recursive_outputs_text_only && mkdir -p recursive_outputs
cp anibon_timestamper_state.json anibon_timestamper_state_text_only.json
rm -f anibon_timestamper_state.json all_timestamps.txt anibon_timestamps.md timestamper.pid
3. バックグラウンドでのデタッチ起動(3 OS ファミリー)

推論をバックグラウンドでデタッチして実行するため、エージェントのセッションやタイムアウトによって実行が停止することはありません。

macOS(Zsh / Bash):

./scripts/launch_local.zsh ~/youtube_<VIDEO_ID>_workspace 100.115.25.30 auto th

Linux(Bash):

./scripts/launch_local.sh ~/youtube_<VIDEO_ID>_workspace 100.115.25.30 auto th

Windows(PowerShell):

powershell -ExecutionPolicy Bypass -File "scripts\launch_local.ps1" -Workspace "$HOME\youtube_<VIDEO_ID>_workspace" -Endpoint "100.115.25.30"

Windows(CMD バッチ):

scripts\launch_local.bat "%USERPROFILE%\youtube_<VIDEO_ID>_workspace" 100.115.25.30 auto th

メモ

エンドポイントの自動プローブとフォールバック規則:すべてのランナーと Python クライアント(anibon.lmstudio.resolve_endpoint())は、TCP ソケットテスト(1.0 秒)で http://100.115.25.30:1234 を自動的にプローブします。接続できない場合(ローカルホスト自体での実行を示します)、直ちに安全に http://127.0.0.1:1234 にフォールバックします。

ヒント

リモート / TokenMe エンドポイントのサポート: 環境変数または --api-key で TOKENME_API_KEY(または LM_API_KEY)を渡すことで、TokenMe(--endpoint https://api.tokenme.limited/v1 または api.tokenme.limited)などの OpenAI 互換リモートエンドポイントを指定できます。

  • クライアントは標準の Authorization: Bearer <KEY> ヘッダーとブラウザーの User-Agent ヘッダーを設定し、Cloudflare WAF コード 1010 を回避します。
  • nvidia/Gemma-4-26B-A4B-NVFP4 のようなリモートモデルは、base64 の image_url ペイロードを使ったマルチモーダルな画像検査をすぐにサポートします。

ヒント

設定(config.json と --config): 数値定数、トークン制限、タイムアウト、温度、プルーニングの上限、デフォルトのエンドポイントは skills/anibon-timestamper-local/config.json で管理され、anibon/config.py によって依存関係なしで自動的に読み込まれます。

  • 秘密情報(TOKENME_API_KEY や LM_API_KEY など)は .env(gitignore 対象)に保存してください。
  • 特定の実行やハードウェア構成に合わせてパラメーターをカスタマイズするには、JSON 設定ファイルをコピーまたは作成し、--config /path/to/config.json(後方互換性のための --env-file も可)を渡します。
  • 環境変数(ANIBON_CHUNK_MAX_TOKENS、ANIBON_TEMPERATURE など)は、ファイルを変更することなく config.json の値をシームレスに上書きします。
4. 文字化け収集と Whisper による正解データ(自動ポストパス)

anibon_timestamps.md の要約の組み立てが完了すると、process_chunks_local.py は <workspace>/garbled_notes_raw/ に残っている音声表記の文字化けを自動的に確認し、ローカルの whisper.cpp で音声を切り出す whisper_dispatcher.py を呼び出して、garbled_replacements.json を更新します。

  • 音声をすべてダウンロードせず、ストリームをその場で切り出すために動画 URL を渡すには:
    python3 -X utf8 scripts/process_chunks_local.py "~/youtube_<VIDEO_ID>_workspace" \
        --video-url "https://www.youtube.com/watch?v=<VIDEO_ID>"
    
  • 文字化けの自動収集パスを無効にするには:
    python3 -X utf8 scripts/process_chunks_local.py "~/youtube_<VIDEO_ID>_workspace" \
        --no-garbled-collector
    
  • 文字化けの収集を任意のタイミングで手動実行するには:
    python3 scripts/whisper_dispatcher.py ~/youtube_<VIDEO_ID>_workspace \
        --video-url "https://www.youtube.com/watch?v=<VIDEO_ID>" --verbose
    python3 ../cleaning-auto-transcripts/scripts/update_garbled_dictionary.py \
        --from-notes ~/youtube_<VIDEO_ID>_workspace/garbled_notes.json \
        --workspace ~/youtube_<VIDEO_ID>_workspace
    
5. 世界観の同一性と事実確認の監査(必須工程)

all_timestamps.txt と anibon_timestamps.md を生成した直後に、以下を行います。

  1. anibon-world-identity を読み込みます:出力したすべてのタイムスタンプのタイトルと説明を、ローカルのナレッジベースと照合します。
    • FGO のサーヴァント/クラス:atlas_fgo.db を検索します(芦屋道満をアスカロン/アスクレピオスと混同しないでください)。
    • ポケモンの登場人物・要素:pokemon.db を検索し、タイのコミュニティ名/公式名を優先します(例:แบกซ์แคลิเบอร์ (Baxcalibur))。
    • アニメ/ガチャのタイトル:references/*.md と照合します(例:Chaos_Zero_Nightmare.md、Genshin_Impact.md、Honkai_Star_Rail.md、Wuthering_Waves.md)。
    • 新作の対戦ゲーム(Deadlock など):ウェブ検索またはパッチノートで、ヒーロー名(Baba/Baba Yaga、Celeste、Abrams)を照合します。
  2. 固有名詞を修正します:聞き間違いによるずれ、誤認したタイトル、LLM の幻覚を anibon_timestamps.md で直接修正します。
  3. 知識を保存します:
    • 確認済みの聞き間違いパターン(例:เคราสเซียร์นี้แม่ → Chaos Zero Nightmare、อัชเฉร้อน → อาชิยะ โดมัน)を、ルートとスキルのリソースにある garbled_replacements.json に追加します。
    • 新たに確認したシリーズ/キャラクターを anibon-world-identity/references/ に追加します。

規律と自己正当化の防止

ローカル処理の鉄則
NEVER TIME-LOCK TOPICS TO ARBITRARY MINUTE BOUNDARIES

ライブ配信の内容は自然に流れていきます。一定の $N$ 分ごとにスタンプを付けるのではなく、再帰的ローリング要約ステートマシンを使用して、実際の内容の切り替わりを検出してください。

自己正当化一覧
自己正当化実態対策
「単一チャンクのほうが処理が速い。」35 個以上のマイクロスタンプが生成され、コメント欄が見づらくなります。ローリング要約を使い、--mode recursive を指定します。
「内容に合うから、[วิเคราะห์] のようなタグを作ってもいい。」最上位層のベンチマークでは標準外のタグが拒否され、コメントのパーサーが壊れます。ノーマライザーが [วิเคราะห์] → [Talk] に自動で置き換えます。
「3 時間分の文字起こし全体を、1 つのプロンプトで要約しよう。」コンテキストの上限を超え、12B モデルでの固有名詞の再現精度が低下します。順次処理するローリングステートマシンにより、プロンプトを 2k トークン未満に保ちます。
「これを速く処理するために、専用の Python スクリプトを書こう。」場当たり的なスクリプトは、状態追跡、再開ロジック、エンコーディングを壊します。process_chunks_local.py のフラグのみを厳守して使用します。
「世界観の同一性を確認しなくても、タイムスタンプは十分よく見える。」カットオフ後のゲームを幻覚したり、コミュニティで使われるタイ語の音写を使わず、ポケモン名を英語表記のまま使ったりします。最終引き渡し前に、必ず /anibon-world-identity のチェックを実施します。
危険信号 — 停止してやり直してください
  • /anibon-world-identity でシリーズの登場人物・要素を照合せずに、タイムスタンプをユーザーに渡す。
  • 文字起こしの復元パイプライン(whisper-corruption-recovery)が 100% 完了し、検証される前に、タイムスタンプ生成を実行しようとする。
  • 2 時間の配信に対し、出力ファイルに 35 個以上のタイムスタンプが含まれている(マイクロスタンプ化の兆候)。
  • 出力タグに許可リスト外の語句([วิเคราะห์]、[ชำแหละ]、[เปิดตัว])が含まれている。
  • 話題を過剰に細分化し、マイクロパートに分割しすぎている(配信あたり 6~8 パート超)。コメントのバイト数制限に無理に合わせるより、視聴者の移動しやすさとテーマの一貫性を優先します。
  • スクリプトが UnicodeEncodeError: 'charmap' でクラッシュする(-X utf8 を忘れています)。
  • 終了チャンクが継続扱いになっているため、締めの部分が抜けている。必ず最後の 5 分間を確認し、締めのスタンプがあることを確かめてください。
  • 新しいゲームが起動された後、終盤のゲーム内メカニクス(「หอรี」、「เฟ้อกว่าเวเนซุเอลา」)を、以前に話していたゲームのものとして扱う。
  • シリーズとの事前学習上の関連付けだけを根拠に、言及されていない設定や章のタイトル(例:「Lostbelt」)を幻覚する。
  • カスタムアバター付きの視聴者の投げ銭通知を、文字どおりの商品レビューやフィギュア紹介としてラベル付けする([Talk] โชว์ฟิกเกอร์)。
ストリーム終了/アウトロの不変条件

--mode recursive では、長時間途切れずに続くゲームプレイや締めくくりの配信において、is_continuation=True によってストリームのアウトロが取り込まれてしまわないようにしてください。 トランスクリプトの最後の5分間は、必ず締めくくりの語句(ขอบคุณครับ、ลงไลฟ์、ราตรีสวัสดิ์、เจอกัน、บ๊ายบาย)を確認し、次の項目を出力してください。

  1. スーパーチャット/誕生日のお祝い:支援者一覧、スーパーチャット、メンバーへの誕生日のお祝いを読み上げる場合は、[Donation] を使用します(HH:MM:SS - [Donation] ปู่โบ๊ตขอบคุณผู้ชม ผู้สนับสนุนโดเนท และอวยพรวันเกิดสมาชิก)。
  2. 締めの挨拶:最後のまとめの発言と次回配信のお知らせには、[Ending] を使用します(HH:MM:SS - [Ending] ปู่โบ๊ตกล่าวปิดสตรีม...)。
  3. 定例ライブ配信のガードレール:Pu Boat は22:00に特撮配信(「ไลฟ์โทกุ」「คอนเทนต์โทกุ 3 เรื่อง 3 รส」)を頻繁に予定します。音声認識による音声上の誤認識(โทกกู、ทั่วกุ、คอนเทนทุกคึ)は、必ず โทคุซัตสึ (Tokusatsu) に対応させ、「Tokyo Ghoul」としては絶対に扱わないでください。
マクロテーマ別のパート分けに関する不変条件(3,500バイト上限による過剰分割の禁止)

タイムスタンプは、広範で一貫性のあるマクロテーマ別のパート(長時間の配信では通常4~6パート)に厳密にまとめます。 視聴者のナビゲーションとテーマの一貫性を優先し、シリーズ全体のレビュー、メディアの同時視聴会、ゲームプレイなど、関連する話題は1つのパートにまとめてください。単一コメントのバイト数制限に合わせるために、恣意的に10~18個の小さなパートへ分割してはいけません。 assemble_parts() と run_local_summarizer_pass() は、デフォルトではバイト数の上限を適用しません。enforce_byte_cap() は、単一コメントの分割が明示的に要求された場合にのみ使用する、オプトインのユーティリティとして保持します。

厳選した重要タイムスタンプの選定に関する不変条件

長時間のライブ配信(4~8時間)からタイムスタンプを作成する場合は、次の運用基準に従ってください。

  1. 主な出力の方針:主要な成果物として、厳選した重要版(7~8時間の配信では約40~60個のタイムスタンプ、またはマクロテーマ別の各パートにつき約8~15個)を提示します。
    • 重要タイムスタンプの自動絞り込み(prune_essential):60個を超えるタイムスタンプが生成された場合、finalize_and_assemble_timestamps() はローカルモデルに自動で問い合わせ、重要な転換点、ニュース、ゲームプレイの節目、主要な結論を約40~60個に絞り込みます。パイプラインは生のタイムスタンプとの厳密な逐語一致を強制し、配信開始時と [Ending] のタイムスタンプが必ず残るようにします。LLM 呼び出しに失敗した場合も、適切にフォールバックします。
  2. 重要項目の選定基準:
    • 主要な話題の開始点または転換点(話題の切り替わり/転換点)。
    • 公式ニュース、発表、リリース、統計データ(公式ニュース、リリース、データ)。
    • 詳細な分析の結論と主要な要点(詳細な分析と主要な要点)。
    • ゲームプレイの重要な節目(チュートリアル開始、新しいキャラクター/スキルの探索、重要アイテムの作成、ボスの出現、注目の戦闘、勝利/敗北)。
    • 配信のアウトロと締めくくりのお礼(配信のアウトロ)。
  3. 細かなタイムスタンプの絞り込み:
    • 短い時間内に同じ論点が繰り返される細かなトークのタイムスタンプは減らしてください(例:配信者がある論点を5~10分かけて掘り下げる場合、2分ごとにタイムスタンプを付けないでください)。
    • 本筋に影響しない雑談、ちょっとした冗談、軽口のタイムスタンプは減らしてください。
  4. 2種類のファイルへの保存:
    • 厳選した重要タイムスタンプのファイルを anibon_timestamps_essential.md(または anibon_timestamps.md)に保存します。
    • 参照やアーカイブ検索に備えて、時系列順の網羅的なタイムスタンプログを anibon_timestamps_full.md(および all_timestamps.txt)に保持します。
マクロテーマの境界を適切な位置に合わせる不変条件

主要な分野/話題の切り替わり(例:タイ政治 → アニメ/シリーズのレビュー、ゲームプレイ → スーパーチャットのQ&A)は、無関係な話題のセクションの末尾に、取り残されたタイムスタンプが1~4個並ぶ形で始めてはいけません。 assemble_parts() は find_best_boundary() を使って、切り替わりを示すマーカー(สรุปการพูดคุย... และเตรียมเปลี่ยนไปคุย、เตรียมเริ่มเล่นเกม、เตรียมเข้าสู่ช่วง)に合わせてパートの境界を自動調整します。これにより、取り残されたタイムスタンプのない、視聴者にとって分かりやすく、話題ごとに整理された構成になります。

タイムスタンプの導入部と比喩の帰属に関する不変条件
  1. 導入部の基準点:タイムスタンプの開始時刻は、必ずトピックの導入文を基準にします。文の途中にキーワードが現れる時刻、またはそれ以降にタイムスタンプを設定してはいけません。リンクをクリックした視聴者が、10〜20秒前に話された重要な文脈を聞き逃さないようにするためです。
  2. 軽い言及による比喩のルール:わずかに(1〜2文)触れられただけの作品名、人名、地名を、タイムスタンプのメインタイトルとして比喩や修辞的な比較に使ってはいけません。
    • 誤り: Comparing standards... with Frieren(トピックが『ワンパンマン』第3期への批評であり、『葬送のフリーレン』は比較のための一文で触れただけの場合)。
    • 正しい例: Critiquing One Punch Man Season 3 and J.C.Staff's 'watchable' standard (noted that it cannot compare to major productions like Frieren)
ワールドアイデンティティ監査に関する不変条件

すべての固有名詞、ゲームタイトル、キャラクター名に対して anibon-world-identity 監査を実施せずに、最終的なタイムスタンプ出力を絶対に行ってはいけません。Thai Whisper の出力は音声を音素で表記します。ローカル LLM は、聞き慣れないゲーム名(CZN、Deadlock など)を、よく知られたゲーム(Genshin、Dota)と誤認して幻覚することがあります。ローカルの参照資料(references/*.md)とカード/エンティティのデータベース(atlas_fgo.db、pokemon.db)は、モデルの記憶よりも優先されます。process_chunks_local.py は完了時に、生成された anibon_timestamps.md を <workspace>/entity_glossary.json と自動的に照合し、確認済みの音声表記の異形を置き換えます。

配信タイトルのトークン照合に関する不変条件

配信自体の YouTube メタデータ(info.json のタイトル、説明欄)にある固有名詞、Mod 名、フランチャイズ名は、正解を示す基準点です。

  1. タイトル内のトークンを優先:出力されたタイムスタンプの説明に、配信タイトル内に存在するエンティティの音声的な類似表記または省略形が含まれている場合(ASR が Vity と書き起こした一方で、タイトルには Verity と明記されている場合や、Nania と Narnia の場合など)、パイプラインはタイトルの正式な綴りに確実に合わせなければなりません。
  2. タイトルと ASR の音声的なずれ:配信タイトルは、配信者が意図的に取り上げたテーマを示します。動画内で生じた ASR の音声的なずれによって、タイトルで確認済みのエンティティが上書きされたり、表記の精度が損なわれたりしてはいけません。

よくある間違いとトラブルシューティング

  1. LM Studio によるモデルのアンロード:

    • 症状:LM Studio が Gemma 4 をアンロードして別のモデルを再読み込みするため、60 秒間処理が停止します。
    • 対処法:--model auto を維持してください。resolve_model がメモリ上でアクティブなモデルを自動的に固定します。
  2. Gemma 4 の思考トークンの落とし穴:

    • 症状:出力されるタイムスタンプが空白、または途中で切れています。
    • 原因:モデルがトークン予算を reasoning_content に使用しました。
    • 対処法:組み込みのシステムプロンプトで思考を 2 文未満に制限しています。正規表現エクストラクターが、コンテンツまたは推論から構造化 JSON を直接抽出します。
  3. ASR の音声表記のずれ:

    • 症状:「Naucrate (นอคราเต้)」ではなく、「นครโตะ」のような名前が表示されます。
    • 対処法:process_chunks_local.py が resources/default_mappings.json を読み込み、プロンプトを生成する前に TF-IDF 信号検出を実行します。
  4. 画像プロンプトでのマルチモーダルプロジェクター(mmproj)の不足:

    • 症状:画像の検証やストーリーボードの確認に対して、*「画像または動画が見えません」*と応答します。
    • 原因:モデルの GGUF にマルチモーダルプロンプトトークンが含まれていますが、対応する mmproj-*.gguf ファイルを指定せずに LM Studio/llama.cpp に読み込まれています。
    • 対処法:LM Studio のモデル設定または llama-server --mmproj で mmproj ファイルを明示的に指定するか、Qwen2.5-VL-7B のような統合型ビジョンモデルに切り替えてください。
  5. 変更または復元したトランスクリプトでの再実行:

    • 症状:タイムスタンプ処理が 1 秒で終了し、[skip] chunk_XX (already processed) と表示されます。
    • 原因:スクリプトは、チャンクごとの応答を <workspace>/recursive_outputs/chunk_XX.json と anibon_timestamper_state.json にキャッシュします。
    • 対処法:--no-resume を指定し、recursive_outputs/ と anibon_timestamper_state.json を削除してください。
  6. 継続処理の落とし穴によるエンディングの欠落:

    • 症状:出力されるタイムスタンプが動画の終了 30〜60 分前で止まり、配信者の締めくくりの発言が抜けています。
    • 原因:再帰的なローリングモードで is_continuation=True としたため、最終セッションが途切れないゲームプレイとして扱われ、エンディングが破棄されました。
    • 対処法:エンディングの不変条件として、最後の 5 分間を必ずスキャンし、[Ending]/別れの挨拶のタイムスタンプを探してください。
  7. WebP の Content-Type を持つストーリーボード MHTML:

    • 症状:storyboard.mhtml がダウンロード済み(20MB 以上)にもかかわらず、prepare_storyboard_slides() がスライドを 0 枚抽出します。
    • 原因:YouTube の yt-dlp は、ストーリーボードのマルチパートスライドを image/jpeg ではなく、Content-type: image/webp(RIFF...WEBP)としてパッケージすることがよくあります。
    • 対処法:anibon/multimodal.py は image/jpeg と image/webp の両方を確認します。FFmpeg は PIL を必要とせず、どちらの形式からもタイルを切り出し、高解像度の JPEG として出力します。
  8. yt-dlp のストーリーボードにおける --skip-download の落とし穴と空のスライドディレクトリ:

    • 症状:download_storyboard() が終了コード 0 で終了しても .mhtml ファイルが生成されないか、prepare_storyboard_slides() が空の slides_clean/ ディレクトリを返します。
    • 原因:--write-auto-subs --skip-download とは異なり、ストーリーボード(-f sb0/sb1/sb2/sb3)は主要な形式です。--skip-download を渡すと、ストーリーボードがまったくダウンロードされません。また、slide_*.jpg をグロブ検索せずに clean_dir.exists() を確認すると、ディレクトリが空でも誤って存在すると判定されます。
    • 対処法:-f sb0/sb1/sb2/sb3 のダウンロード時には --skip-download を決して渡さず、必ず clean_dir.is_dir() and any(clean_dir.glob("slide_*.jpg")) を確認してください。
  9. マルチモーダルエンドポイントに /v1/chat/completions がない場合(KeyError: 'choices'):

    • 症状:http://host:1234 のようなベースエンドポイントを渡すと、call_multimodal() が KeyError: 'choices' を発生させます。
    • 原因:urllib.request が /v1/chat/completions ではなく、LM Studio のルートエンドポイントにアクセスします。
    • 対処法:call_multimodal() 内で url を正規化し、すでに末尾に含まれていない場合は /v1/chat/completions を追加してください。

コメント