mcpField
A
anibon-timestamper

anibon-timestamper

github.com/zeniththCreative & media190 installsUpdated 1d ago
Repository

About anibon-timestamper

anibon-timestamper is a skill for producing YouTube-format topic timestamps from Anibon Official live-stream transcripts with cloud LLMs. It routes chunks to specialized subagents in parallel and can incorporate chat, stream activity, and topic references.

Key features

  1. 01Parallel chunk analysis by subagents
  2. 02Transcript preparation and chunking
  3. 03Topic signal and boundary detection
  4. 04Optional LiveChat and activity context
  5. 05Mood guidance from chat pulses

Use cases

  1. 01Label topics in Anibon Official streams
  2. 02Process long transcripts in chunk groups
  3. 03Use chat context to characterize stream moments

Install

Copy the command and run it in a terminal.

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

After installing, type/anibon-timestamperin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

.gitignore
docs/superpowers/specs/
2026-08-06-per-chunk-mood-segments-design.md
references/
anibon_emoji_dictionary.md
BUILD_WHISPERCPP_GUILD.md
INDEX.md
subagent-prompt-template.md
summarizer-subagent-guide.md
whisper_pc_spec_benchmark.md
references/stories/
.gitkeep
resources/
garbled_replacements.json
scripts/
align_live_chat.py
anibon-analyzer.py
build_subagent_prompts.py
detect_boundaries.py
detect_signals.py
dump_chunk_text.py
merge_timestamps.py
prepare_video.py
validate_mood.py
validate_part_coherence.py
tests/
__init__.py
test_align_live_chat.py
test_analyze_555_emoji.py
test_detect_signals.py
test_pack_timestamps.py
test_validate_tags.py

Details

From the project README

Anibon Timestamper (Frontier / Cloud Orchestrator)

A routing orchestrator skill for analyzing live stream transcripts using cloud/frontier LLMs to generate timestamps in YouTube format. Dynamically detects stream type and delegates to specialized subagents in parallel.

When to Use

  • Streams or videos by "Boat" from Anibon Official that need timed topic labels using Frontier / Cloud models with parallel subagents (anibon-chunk-timestamper, anibon-summarizer, anibon-garbled-notes).
  • If running locally on a single GPU (NVIDIA Tesla P100, LM Studio, Ollama, local VLM) without cloud API costs, use anibon-timestamper-local instead.

Sub-Skills & Permissions

REQUIRED (first): Load preparing-tools to verify dependencies (yt-dlp, ffmpeg, python3). REQUIRED (subagent execution): Load batching-subagents-concurrency when running multi-subagent analysis (max 10 per batch turn with Model: "flash"). Ask user permission before downloading large external media or performing long web fetches.

Loaded by signal (add to prompt when needed):

  • anibon-world-identity — verify game/char names and Japanese convention/event terms against references before stamps
  • anibon-stream-activity — high-res storyboard sampling for on-screen gameplay, webcam presence/AFK, and visual grounding
  • anibon-local-transcription — whisper.cpp fallback if YouTube has no captions
  • whisper-corruption-recovery — recover transcript if repetition loops / corruption detected in Whisper output
  • anibon-livechat-analysis — parse LiveChat replay (or visual on-screen chat fallback via extract_visual_livechat.py) so subagents can read the live from both sides (talker + chat)
  • antigravity-vision-proxy — storyboard (sb0) frame inspection for ambiguous pronouns, game title verification, or unresolved garbled notes

Pipeline (Linear, Top-to-Bottom)

All paths relative to the skill root directory (skills/anibon-timestamper/).

0. Environment

scripts/ directory contains all helper scripts. Run <script>.py --help for flags. Store working files in youtube_<video_id>_workspace/.

1. Initialize

Ask output language. Verify channel and speaker nicknames against resources/channels.json:

  • Own Channel: Anibon Official (@anibonofficial)
  • Primary Speaker: Boat / Pu Boat (ปู่โบ๊ต / PhuBoat / โบ๊ต)

Ensure transcript speaker attribution maps to own_channel nicknames before continuing.

2. Prepare Video
python3 -X utf8 scripts/prepare_video.py "URL" --format xml --block 300 --overlap 30
# Talk-heavy → --block 600 --overlap 60

Downloads transcript, creates <workspace>/chunks/chunk_*.xml.

Important

Check Corruption: If transcript is from local Whisper transcription (or audio ≥2h), verify tail entries for repetition loops. If corruption found (>0.5 match ratio), load whisper-corruption-recovery skill to split, re-run corrupted tail segment, and dedup-merge before chunking.

3. Clean Transcript (Optional)

Normalizes Thai-Whisper garbled English before signal detection. The script lives in the cleaning-auto-transcripts skill — resolve from the timestamper skill root.

python3 -X utf8 ../cleaning-auto-transcripts/scripts/clean_garbled_english.py --chunks ~/youtube_<id>_workspace/chunks/
3.5 Download & Align LiveChat (Optional but preferred)

Gives each subagent the watchers' chat for its own chunk, so situation + emotion are read from BOTH talks and chat. Requires network; if a VOD has no live_chat subtitle, skip this step and rely on transcript-only emotion.

# 1. Download LiveChat replay (network required)
yt-dlp --sub-langs live_chat --write-sub --skip-download "https://www.youtube.com/watch?v=<VIDEO_ID>" -o "<workspace>/%(id)s.%(ext)s"
# 2. Parse to coarse chunks + a seconds-prefixed raw event feed
python3 -X utf8 ../anibon-livechat-analysis/scripts/parse_live_chat.py <workspace>/<id>.live_chat.json --chunk-minutes 90 --raw-events <workspace>/livechat_events.txt -o <workspace>/livechat_90/
# 3. Align raw feed to transcript chunk windows
python3 -X utf8 scripts/align_live_chat.py --events <workspace>/livechat_events.txt --chunks <workspace>/chunks/ -o <workspace>/livechat/

Output: livechat/livechat_chunk_NN.txt (per transcript chunk) + livechat/livechat_index.json. If yt-dlp reports no live_chat subtitles, continue — the subagent falls back to transcript-only.

Fallback for Edited Livestreams / Missing .live_chat.json (Visual Chat Extraction)

When a livestream has been trimmed or edited in YouTube Studio, YouTube permanently deletes the .live_chat.json chat replay track, and yt-dlp will report no chat subtitles available.

Instead of losing watcher context on high-interest moments, run extract_visual_livechat.py from anibon-livechat-analysis to OCR the burned-in chat overlay for specific peak chunks (e.g. meme bursts, high SuperChat donations, viewer Q&As, or climax reactions):

# 1. Spot-extract visual livechat for target chunk time range
python3 -X utf8 ../anibon-livechat-analysis/scripts/extract_visual_livechat.py \
  --video-id <VIDEO_ID> \
  --range HH:MM:SS-HH:MM:SS \
  -o <workspace>/visual_livechat_events.txt

# 2. Align visual raw event feed directly to chunk windows
python3 -X utf8 scripts/align_live_chat.py \
  --events <workspace>/visual_livechat_events.txt \
  --chunks <workspace>/chunks/ \
  -o <workspace>/livechat/

This populates <workspace>/livechat/livechat_chunk_NN.txt for the targeted chunk windows, feeding directly into analyze_555.py (Step 3.7) and subagent prompt generation without requiring a full-length video download.

3.6 Extract Activity & Webcam Timeline (Optional but preferred)

Captures on-screen gameplay/web browsing and Pu Boat's webcam presence/AFK state to eliminate Speech vs. Action divergence errors.

# 1. Download high-res storyboard (sb3 -> sb2 -> sb1 -> sb0)
yt-dlp -f "sb3/sb2/sb1/sb0" "https://www.youtube.com/watch?v=<VIDEO_ID>" -o "<workspace>/frames/storyboard.%(ext)s"
# 2. Unpack slides
python3 -X utf8 ../anibon-stream-activity/scripts/unpack_storyboard.py --mhtml "<workspace>/frames/storyboard*" --out-dir "<workspace>/frames/slides"
# 3. Extract continuous activity timeline
python3 -X utf8 ../anibon-stream-activity/scripts/extract_activity_timeline.py --slides-dir "<workspace>/frames/slides" -o "<workspace>/activity_timeline.json"
# 4. Align activity to chunk windows
python3 -X utf8 ../anibon-stream-activity/scripts/align_activity_timeline.py --timeline "<workspace>/activity_timeline.json" --chunks "<workspace>/chunks/" -o "<workspace>/activity/"

Output: <workspace>/activity/activity_chunk_NN.txt containing on-screen game/app state, webcam presence, and physical expressions for subagent injection.

3.7 Detect Thai-Laugh / Meme Pulses (Optional but preferred)

Downstream of align_live_chat.py. Thai watchers mark laughter with 555... / xD / ฮา / ขำ. A clustered burst in a short window = a meme/laugh peak. This is the only reliable laugh proxy when the autotranscript can't hear the streamer actually laughing. Emits per-chunk mood verdicts + Thai tone guidance that subagent prompts MUST weight when writing mood-bearing descriptions.

python3 -X utf8 scripts/analyze_555.py \
  --livechat ~/youtube_<id>_workspace/livechat/ \
  --index ~/youtube_<id>_workspace/livechat/livechat_index.json \
  --out ~/youtube_<id>_workspace/mood_555.json

Output: mood_555.json — dict chunk → {density, n_markers, n_messages, peak_windows, pulse, mood, verdict, tone}. The tone field carries Thai guidance (tone + suggested verbs) matched to the chunk's mood family. Verdicts:

  • *_PULSE — burst passed the weighted score → mood-driven guidance. MEME_PULSE (funny), CUTE_CUNNY_PULSE (cute), SHOCK_HYPE_PULSE (hype), DRAMA_NEWS_PULSE (news/drama), ANGRY_OUTRAGE_PULSE (rant), etc.
  • HOT / WARM — some markers, no burst → light banter / lively guidance
  • QUIET — low chat, no burst → neutral, free verb choice

Note

Mood is guidance, not a rule. The tone/verbs hint tells the subagent which vibe the chat carried; the AI still picks its own first verb from the situation. Only when a PULSE chunk gets timestamped as if the moment were flat does validate_mood.py (Step 11.5) remind the human.

Emoji Dictionary Reference: Refer to references/anibon_emoji_dictionary.md for complete channel-exclusive emote mapping (:_CunnyBoat:, :_MonkeyBoat:, :_Nerd:, :_shutup:, :Grind:, :_Ripfish:, :_noname:, :_What:, :_WOW:, :_Ahh:, :_Meh:, :_MoneyBoat:, :_Tahaan:, :_KonDee:, :_NeoSlim:, :_Slim:, :_BoatSOM:) and YouTube global emotes to mood pulse weights and safety masking triggers.

If a chunk is flagged MEME_PULSE but the subagent writes a flat, factual first-verb for it, that's the tone mismatch validate_mood.py (Step 11.5) surfaces for review.

4. Analyze (Pre-flight)

Quick summary of chunk categories, gaps, byte sizes. Note: On Windows, use -X utf8 to avoid console UnicodeEncodeError.

python3 -X utf8 scripts/anibon-analyzer.py ~/youtube_<id>_workspace/
5. Detect Signals → Match Knowledge Files

TF-IDF across all chunks. Matches keywords to knowledge files per chunk.

python3 -X utf8 scripts/detect_signals.py \
  --chunks ~/youtube_<id>_workspace/chunks/ \
  --knowledge ./resources/knowledge.json \
  --output ~/youtube_<id>_workspace/signals.json

Output: signals.json — per-chunk weighted signal: matched_files (with df/weight), weighted_matched_files (ranked), best_file, primary_topic, confidence.

Path convention: every best_file/matched_files path in knowledge.json is relative to the timestamper skill root. references/stream/*.md = local to timestamper; ../anibon-world-identity/references/*.md = world-identity skill; ../reference/* = top-level data dir. Resolve all of them from the timestamper root, never from the current cwd.

Rarity = main idea: detect_signals.py weights each matched keyword by inverse document frequency (log(N/df)). High-frequency (df high) words are daily-use filler and score 0 — ignored. Low-frequency (rare) words are the distinctive main idea. Hand best_file to a subagent only when confidence is clear; otherwise omit the knowledge file.

5.5 Load World-Identity (if signals match a game reference)

Trigger: signals.json best_file/weighted_matched_files resolves to a file under ../anibon-world-identity/references/ (i.e. post-cutoff game/char names). These names are the ones subagents hallucinate.

Action: Load the anibon-world-identity skill. It runs references/INDEX.md → cached story refs → reference SRT → websearch fallback to build a verified Thai-phoneme → EN name map. Bootstrap its game DBs first:

python3 ../anibon-world-identity/scripts/fetch_fgo_db.py --check --db "../reference/FGO and DATA/atlas_fgo.db" || \
  python3 ../anibon-world-identity/scripts/fetch_fgo_db.py --db "../reference/FGO and DATA/atlas_fgo.db"
python3 ../anibon-world-identity/scripts/fetch_ygo_db.py --check --db "../reference/Yu-Gi-Oh DATA/ygo_cards.db" || \
  python3 ../anibon-world-identity/scripts/fetch_ygo_db.py --db "../reference/Yu-Gi-Oh DATA/ygo_cards.db"

Inject the resolved name map into the Step 7 subagent prompts (any chunk whose signal matches one of these files) so [Story] stamps use canonical names, not phonetic guesses. Skip when stream covers well-known pre-cutoff content.

6. Detect Topic Boundaries (Optional)

For long streams with clear topic shifts. Run:

python3 -X utf8 scripts/detect_boundaries.py --chunks ~/youtube_<id>_workspace/chunks/ --signals ~/youtube_<id>_workspace/signals.json --output ~/youtube_<id>_workspace/boundaries.json

If boundaries look noisy, fall back to manual identification from signals.json: look for chunks where matched_files changes (e.g., gaming→Genshin→FGO). Note timestamps for --break-at in Step 9.

7. Spawn Subagents (Parallel)

Divide chunks into groups of 4–5 (~20–25 min each). One anibon-chunk-timestamper per group.

Run build_subagent_prompts.py to prepare input files:

python3 -X utf8 scripts/build_subagent_prompts.py <workspace>

This produces:

  • <workspace>/prompts_by_chunk/chunk_NN.txt: per-chunk prompt files (~15–25KB each, guaranteed under view_file's 46KB view limit to prevent mid-chunk truncation).
  • <workspace>/prompts/group_NN.txt: group manifests listing chunk file URIs and metadata.

Important

Strict Concurrency Batching (4–6 Subagents Recommended): To prevent API 429 RESOURCE_EXHAUSTED rate limits (especially rolling TPM exhaustion when group manifests reach ~50–100KB), launch subagents in controlled batches of 4–6 subagents per turn (max 8). Wait for each batch to finish, and ONLY THEN launch the next batch.

Use Flash Model Tier: Always specify Model: "flash" when calling invoke_subagent for chunk timestampers to maximize speed and rate-limit headroom.

Per-Chunk Sequential Reading: Point subagents to sequentially read their assigned file://<workspace>/prompts_by_chunk/chunk_NN.txt files via view_file to ensure 100% full-text reading without truncation.

Invoke pattern (one per group):

invoke_subagent(
    "anibon-chunk-timestamper",
    Model="flash",
    prompt=f"""You are processing Group {g} (chunks {start} to {end}).
PREVIOUS GROUP LAST TOPIC: {prev_topic}
Read each chunk sequentially via view_file:
- file://{workspace}/prompts_by_chunk/chunk_00.txt
- file://{workspace}/prompts_by_chunk/chunk_01.txt
..."""
)

Each chunk prompt contains:

  • Chunk XML/dialogue lines
  • Detection signals from signals.json (best_file + primary_topic + confidence + ranked weighted_matched_files)
  • Per-chunk LiveChat log (livechat/livechat_chunk_NN.txt)
  • Per-chunk on-screen visual activity log (activity/activity_chunk_NN.txt)
  • Per-chunk mood verdict + tone guidance from mood_555.json

CRITICAL: The agent reads chunks sequentially within its group and skips continuation chunks. Do NOT inject your own topic summaries — inject signals data only.

Each anibon-chunk-timestamper returns plain-text timestamp lines (typically 2–4 per group).

Important

Visual AI & Generative Tool Grounding: When the streamer tests or reacts to visual AI generators (e.g. text-to-image, video generation, or creative editing tools), distinguish between:

  1. The actual prompt requested by the streamer.
  2. What the AI model actually rendered on screen (or if it failed/refused).
  3. The streamer's comedic, political, or hyperbolic satirical roasts. NEVER take satirical roasts (e.g., "กลายเป็นคอมมิวนิสต์", "เหมือนสลิ่ม", "หลอนเป็นเปรต") as literal descriptions of the generated image. Always use [Reaction] and attribute the roast clearly (e.g. ปู่โบ๊ตเหวอ TH-AI ไม่รู้จัก Jane Doe เจนเป็นสาวไซเบอร์ยืนคู่ ครม. แซวยังกะรัฐบาลจีน).

Important

Timestamp Lead-in & Off-hand Analogy Guard:

  1. Lead-in Anchor: Always anchor timestamp start to the opening sentence of a discussion topic. Never stamp mid-sentence after key proper nouns have already been uttered (prevents viewers from clicking and missing context).
  2. Off-hand Analogy Rule: Never elevate passing 1–2 sentence analogies or sarcastic roasts (e.g. comparing a show's budget to Frieren) into the primary timestamp title. Always describe the core topic (e.g. One Punch Man S3 & J.C.Staff drama) and relegate passing comparisons to parentheticals.
8. Merge Timestamps

Write each subagent's output to its own file (e.g., chunk_001.txt, chunk_002.txt). Then merge + sort chronologically:

python3 scripts/merge_timestamps.py ~/youtube_<id>_workspace/chunk_*.txt \
  -o ~/youtube_<id>_workspace/all_timestamps.txt
8.5. Audit Gaps (MANDATORY before summarizer)

Enforces the NO GAPS iron rule. Run on the merged list; if it exits non-zero, spawn a fill agent for each flagged chunk (the tool prints the covering chunk_NN to re-run) and re-merge before Step 9.

python3 scripts/audit_gaps.py ~/youtube_<id>_workspace/all_timestamps.txt
# exit 0: no gaps. exit 1: prints e.g. "12m 01:13 -> 01:25 (fill around chunk_26)"
8.6 Dispatch Audio Slices to Whisper.cpp & Clean Garbled Notes (Ground Truth)

Subagents strictly emit spotter tokens (- "token" @ HH:MM:SS (chunk_NN)). Execute in two distinct phases:

Step 8.6a: Run whisper.cpp First (Orchestrator Audio Ground Truth)
  1. Extract all spotter notes from chunk timestamp outputs into <workspace>/garbled_notes_raw/candidates.txt.
  2. Run whisper_dispatcher.py to cluster timestamps, slice audio on-the-fly, and transcribe acoustic ground truth via local whisper.cpp:
# Slicing & Audio Resolution:
# Option A (Recommended): Direct on-the-fly slicing from stream URL (no multi-GB download required)
python3 scripts/whisper_dispatcher.py ~/youtube_<id>_workspace --video-url "https://www.youtube.com/watch?v=<VIDEO_ID>" --verbose

# Option B (Local audio stream copy at 150x-300x speed without full video download):
URL=$(yt-dlp --extractor-args "youtube:player_client=android" -g -f 18 "https://www.youtube.com/watch?v=<VIDEO_ID>")
ffmpeg -y -i "$URL" -vn -c:a copy ~/youtube_<id>_workspace/audio.m4a
python3 scripts/whisper_dispatcher.py ~/youtube_<id>_workspace --verbose

This produces <workspace>/garbled_notes.json containing:

  • google_sentence: Exact surrounding sentence window from raw_transcript.th-orig.json3.
  • whisper_segment: Time-aligned acoustic sentence segment from whisper.cpp (-oj).
  • correct: Canonical target (auto-resolved from dictionary or set by subagent).

Tip

Failed Slice Recovery (Single Cluster): If any cluster fails to slice (e.g. exit status 187 due to transient stream socket timeout):

URL=$(yt-dlp --extractor-args "youtube:player_client=android" -g -f 18 "https://www.youtube.com/watch?v=<VIDEO_ID>")
ffmpeg -y -ss <start_sec> -t <duration_sec> -i "$URL" -ar 16000 -ac 1 -c:a pcm_s16le <workspace>/audio_slices/cluster_XXX_<start_sec>.wav
/Users/zenithth/whisper.cpp/build/bin/whisper-cli -m /Users/zenithth/whisper.cpp/models/ggml-large-v3-turbo.bin -f <workspace>/audio_slices/cluster_XXX_<start_sec>.wav -l th --output-txt

Update garbled_notes.json with the transcript text before passing to anibon-garbled-notes.

Step 8.6b: Call anibon-garbled-notes Subagent Later (Ground Truth Alignment & Dictionary Sync)

Invoke anibon-garbled-notes subagent with the acoustic transcripts from whisper_dispatcher.py:

invoke_subagent(
    "anibon-garbled-notes",
    Model="flash",
    Prompt=f"""Analyze the whisper.cpp transcripts in {workspace}/garbled_notes.json.
Perform sentence-level word-by-word sequence alignment between google_sentence and whisper_segment to resolve phonetic noise slots.
Resolve canonical words, validate anti-cascade rules against raw_transcript.th-orig.json3,
update {workspace}/garbled_notes.json with confirmed targets, and run update_garbled_dictionary.py."""
)

The subagent updates <workspace>/garbled_notes.json and executes:

python3 ../cleaning-auto-transcripts/scripts/update_garbled_dictionary.py \
  --from-notes ~/youtube_<id>_workspace/garbled_notes.json \
  --workspace ~/youtube_<id>_workspace

# If /Users/zenithth/abss-dev exists, sync git working copy as well:
if [ -d "/Users/zenithth/abss-dev" ]; then
  python3 /Users/zenithth/abss-dev/skills/cleaning-auto-transcripts/scripts/update_garbled_dictionary.py \
    --from-notes ~/youtube_<id>_workspace/garbled_notes.json
fi

Warning

Avoid --cookies-from-browser on macOS: Extracting browser cookies triggers a GUI Keychain password authentication prompt which hangs headless/CLI background agent tasks. Use --extractor-args "youtube:player_client=android" to cleanly bypass YouTube SABR HTTP 403 errors without credentials.

Caution

Anti-Cascade Ground Truth Check: Always cross-check candidate garbled notes against raw_transcript.th-orig.json3. If a candidate contains a multi-word game/anime title (e.g. Yuri on Ice, Chaos Zero Nightmare, Where Winds Meet, SLAPP) embedded inside Thai text, it is an artifact of an aggressive cleaner rule. Never save cleaner artifacts into garbled_replacements.json.

Outputs:

  • ~/youtube_<id>_workspace/garbled_notes.json — all candidates (garbled, google_sentence, whisper_segment, correct, chunk, ts, cluster_span)
  • resources/garbled_replacements.json — auto-synced across root and skill resources with canonical grouped mappings (TargetWord: [patterns...])

The dictionary is shared (resource_path() walks up to plugin root), so every future stream auto-loads the new rules. Truly unresolved proper nouns are left correct: null for human confirmation.

9. Final Assembly — anibon-summarizer (Replaces wrap + pack)

Pass the full sorted all_timestamps.txt to the anibon-summarizer subagent. It deduplicates cross-chunk overlaps, groups by macro-thematic coherence (without 3,500-byte cap over-splitting), curates essential timestamps (~40–60 stamps for long streams), writes caveman part headings, and produces the final markdown.

with open("all_timestamps.txt") as f:
    merged = f.read()

invoke_subagent(
    "anibon-summarizer",
    prompt=f"TIMESTAMPS:\n{merged}"
)

The subagent outputs the complete output.md directly. Save it to ~/youtube_<id>_workspace/output.md.

Note

pack_timestamps.py is still available for offline/scripted runs or when single-comment byte splitting is explicitly requested. In standard sessions, prioritize macro-thematic grouping and essential curated timestamps to preserve topical cohesion. If single-comment byte limits are explicitly requested:

python3 scripts/pack_timestamps.py ~/youtube_<id>_workspace/all_timestamps.txt \
  --byte-limit 2900 \
  --title "<Stream Title>" \
  --output ~/youtube_<id>_workspace/output.md
python3 scripts/check_sections.py ~/youtube_<id>_workspace/output.md
10. Validate Sections
python3 scripts/check_sections.py ~/youtube_<id>_workspace/output.md

Checks: byte cap per section ✅, no ASR garbled patterns.

11. Validate Topic Coherence (Optional)

Cross-references timestamp game names against signals.json ground truth. Flags fabricated names or topic bleed between parts.

python3 scripts/validate_part_coherence.py ~/youtube_<id>_workspace/output.md \
  --signals ~/youtube_<id>_workspace/signals.json \
  --chunks ~/youtube_<id>_workspace/chunks/
11.5 Validate Mood vs Chat Pulse (Optional)

Companion to analyze_555.py. Labels each timestamp with its chunk's mood + Thai tone guidance (the verbs the AI may draw from). Guidance-only — it never rejects a verb; the AI's verb creativity stays free. Report-only; exit 0. Use it to review whether a PULSE-span stamp actually carried the chunk's energy.

python3 scripts/validate_mood.py \
  --timestamps ~/youtube_<id>_workspace/all_timestamps.txt \
  --mood ~/youtube_<id>_workspace/mood_555.json \
  --livechat ~/youtube_<id>_workspace/livechat/ \
  --index ~/youtube_<id>_workspace/livechat/livechat_index.json
12. Catalog, Archive & Dictionary Synchronization (End-of-Series Protocol)

Once output.md is generated and verified (or after a multi-part series run finishes):

  1. Synchronize Garbled Notes:

    • Collect and harvest all spotted GARBLED_NOTES: from chunk timestamper subagents across all parts.
    • Ingest into resources/garbled_replacements.json under the "mappings" key (data["mappings"], preserving header metadata keys version, description, note).
    • Synchronize across both plugin root and vendored copies (resources/garbled_replacements.json and skills/anibon-timestamper/resources/garbled_replacements.json).
    • Commit and push updated dictionary to GitHub (anibon-stream-synthesis.git).
  2. Ingest into timestamp_workspace:

    • REQUIRED SUB-SKILL: Use backing-up-timestamps.
    • Run python3 -X utf8 import_workspace.py ~/youtube_<id>_workspace (or batch across ~/youtube_*_workspace).
    • Automatically archives structured transcripts (transcripts/transcript_<id>.jsonl.gz), copies extras/<id>/, automatically rebuilds the search index (python3 -m anibon_search build), and links entries in by_video_id/timestamp_<id>.md and README.md.
    • Commit and push timestamp_workspace to GitHub (ZenitHTH/timestamp-workspace.git).
  3. Archive Raw Workspaces:

    • Move verified directories into ~/youtube_workspaces/backed_up/.
    • Update workspace_path in metadata/catalog.json.

Output Format

Single .md file with ═══ section blocks:

# Title | ANIBON

═════════════════════════════════════════════════════
 Part 1: Section Header (⏱ เริ่ม: HH:MM:SS)
═════════════════════════════════════════════════════
HH:MM:SS - [Tag] Description
...

═════════════════════════════════════════════════════
 Part 2: Section Header (⏱ เริ่ม: HH:MM:SS)
═════════════════════════════════════════════════════
...

Helper Scripts

ScriptPurpose
scripts/prepare_video.pyDownload + clean + chunk
scripts/dump_chunk_text.pyDump clean formatted text from XML chunks for subagents
scripts/anibon-analyzer.pyPre-flight: gaps, categories, byte sizes
scripts/detect_signals.pyTF-IDF signal + knowledge file matching
scripts/detect_boundaries.pyDetect topic boundaries (feeds --topic-json in Step 9)
scripts/align_live_chat.pySlice LiveChat event feed to per-transcript-chunk logs (Step 3.5)
scripts/analyze_555.pyDetect Thai-laugh/meme pulses from aligned LiveChat → per-chunk mood verdict (Step 3.7)
scripts/validate_mood.pyVerify mood-bearing timestamps honour mood_555 verdicts (Step 11.5)
../anibon-livechat-analysis/scripts/parse_live_chat.pyParse .live_chat.json to event feed (Step 3.5)
../anibon-livechat-analysis/scripts/extract_visual_livechat.pyExtract burned-in on-screen LiveChat via Gemini vision proxy when .live_chat.json is missing (Step 3.5)
scripts/merge_timestamps.pyCombine + sort subagent outputs
scripts/process_chunks_local.pyLocal LLM sequential chunk runner via LM Studio / llama.cpp OpenAI endpoint
scripts/audit_gaps.pyGap audit (NO GAPS rule) + gap→chunk mapping (Step 8.5)
scripts/pack_timestamps.pyByte-limited section packing (supports --break-at, --topic-json)
scripts/check_sections.pyValidate byte cap + ASR garbles
scripts/validate_part_coherence.pyCross-reference game names vs signals
scripts/validate_tags.pyValidate timestamp tag vocabulary
../cleaning-auto-transcripts/scripts/clean_garbled_english.pyNormalize Thai-Whisper garbled English (Step 3)
../cleaning-auto-transcripts/scripts/clean_transcript.pyRaw json3 cleaner (called by prepare_video)
../anibon-world-identity/scripts/fetch_story_ref.pyFetch/cache story synopses (user consent for websearch)
../anibon-world-identity/scripts/align_ref_timeline.pyAlign reference SRT timestamps with chunks
../anibon-world-identity/scripts/fetch_fgo_db.py, fetch_ygo_db.pyBuild card databases (World Identity)

Iron Rules

  • Use named agents — Step 7 MUST use invoke_subagent("anibon-chunk-timestamper") per chunk. Step 8.6 MUST use invoke_subagent("anibon-garbled-notes"). Step 9 MUST use invoke_subagent("anibon-summarizer"). Never substitute a generic Task/self agent.
  • STRICT SUBAGENT BATCHING (4–6 RECOMMENDED) — Process in controlled batches of 4–6 subagents (max 8 with Model: "flash"), wait for completion, then proceed to the next batch. Never launch 10+ subagents simultaneously on heavy prompt jobs.
  • FLASH MODEL TIER FOR CHUNKS — Use Model: "flash" for chunk timestamper subagents to ensure fast execution and avoid API rate limits.
  • NO HEURISTIC / REGEX FALLBACKS — Never fall back to heuristic text-generation scripts if subagents hit errors or rate limits. All timestamps MUST be generated by authentic anibon-chunk-timestamper subagent runs reading real transcript XML and LiveChat logs.
  • Use detect_signals.py — TF-IDF only. No ad-hoc grep/inline scanning.
  • Don't read chunks yourself — subagents read XML. Inject signals.json data into prompts.
  • ONE FILE — single .md with ═══ section blocks. No part1.md.
  • NO GAPS — max 10 min between timestamps unless verified silent.
  • INTRO BREAKDOWN — intro >10 min → break into 3-5 min sub-topic milestones.
  • NO AD-HOC TIMESTAMPS — only via subagent pipeline → merge_timestamps.py → anibon-summarizer.
  • READ BOTH SIDES — subagents must read the ENTIRE transcript chunk AND its LiveChat log (when present) before writing any timestamp. Situation + emotion come from both talks and chat, never from primary_topic alone.
  • HONOUR THE MOOD VERDICT — when mood_555.json exists, inject each chunk's tone guidance (mood + suggested verbs) into the subagent prompt. The AI keeps its own first-verb choice, but must not flatline a chat-laugh/hype peak into a calm factual verb.
  • NON-SPOILER GACHA POLICY — Never spoil whether the streamer won or lost a gacha pull in the timestamp description. Focus on anticipation, the featured banner/character, and chat interactions.
  • 18+ / RULE 34 TONE INTEGRITY — Do not trivialize adult fanart or Rule 34 commentary under generic comedic tags ([Reaction] ฮา...). Use [Talk] with mature, direct, and accurate summaries.
  • PROPER NOUN & GAME TITLE INTEGRITY — When processing garbled notes (Step 8.6), NEVER map legitimate external game titles (e.g. MARVEL Tōkon: Fighting Souls, Alien: Isolation, TMNT: The Last Ronin), brand names, or common English phrases (e.g. where we meet) as noise patterns. Unconfirmed proper nouns must remain correct: null for human review rather than being forced into generic Thai terms.
  • PROPER NOUN IN EVERY STAMP — Every timestamp must name its specific proper noun (e.g. Wuthering Waves, Zelda, น้องเนเน่ AGT, Bleach). Never use vague pronouns ("เกมนี้", "น้องคนนั้น", "ค่ายนี้"). The summarizer must NEVER drop proper nouns; trim adjectives or emotional filler instead.

Comments

Markdown supported