mcpField
A
anibon-timestamper

anibon-timestamper

github.com/zenithth创意与媒体190 次安装1 天前更新
代码仓库

关于 anibon-timestamper

anibon-timestamper 是一项技能,使用云端大模型从 Anibon Official 直播转录稿生成 YouTube 格式的主题时间戳。它将片段并行交给专用子 Agent,也可结合聊天、画面活动和主题参考资料。

主要功能

  1. 01子 Agent 并行分析转录片段
  2. 02准备转录稿并切分片段
  3. 03检测主题信号与边界
  4. 04可选加入 LiveChat 和画面活动
  5. 05根据聊天脉冲提供情绪提示

适用场景

  1. 01为 Anibon Official 直播标注主题
  2. 02分组处理长篇转录稿
  3. 03结合聊天理解直播片段氛围

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/anibon-timestamper确认已加载。

包含的文件

除 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

详细介绍

Anibon 时间戳生成器(Frontier / Cloud Orchestrator)

一种路由编排技能,使用云端 / 前沿大模型分析直播字幕稿,并生成 YouTube 格式的时间戳。它会动态检测直播类型,并行委派给专用子 Agent。

使用场景

  • Anibon Official 的「Boat」直播或视频,需要使用 Frontier / Cloud 模型和并行子 Agent(anibon-chunk-timestamper、anibon-summarizer、anibon-garbled-notes)生成带时间戳的话题标签。
  • 如果在本地运行,使用单块 GPU(NVIDIA Tesla P100、LM Studio、Ollama、本地 VLM),且不想产生云端 API 费用,请改用 anibon-timestamper-local。

子技能与权限

必需(首先加载): 加载 preparing-tools,验证依赖项(yt-dlp、ffmpeg、python3)。 必需(执行子 Agent 时): 运行多子 Agent 分析时,加载 batching-subagents-concurrency(每批次最多 10 个,Model: "flash")。下载大型外部媒体或进行耗时较长的网页抓取前,先征求用户许可。

按信号加载(需要时添加到提示词中):

  • anibon-world-identity — 在生成时间戳前,参照资料核实游戏 / 角色名称及日语惯用表达 / 活动术语
  • anibon-stream-activity — 高分辨率分镜采样,用于判断屏幕上的游戏活动、摄像头画面是否有人 / 是否挂机,以及视觉依据
  • anibon-local-transcription — YouTube 没有字幕时,使用 whisper.cpp 作为备用方案
  • whisper-corruption-recovery — 检测到 Whisper 输出存在重复循环 / 损坏时,恢复字幕稿
  • anibon-livechat-analysis — 解析 LiveChat 回放(或使用 extract_visual_livechat.py 从屏幕画面中提取聊天作为备用方案),让子 Agent 可以同时从主播发言和聊天两方面了解直播
  • antigravity-vision-proxy — 检查分镜(sb0)画面,用于处理指代不明、核实游戏名称或解决无法辨认的笔记

流程(自上而下线性执行)

所有路径均相对于技能根目录(skills/anibon-timestamper/)。

0. 环境

scripts/ 目录包含所有辅助脚本。运行 <script>.py --help 查看参数。 将工作文件存储在 youtube_<video_id>_workspace/ 中。

1. 初始化

询问输出语言。参照 resources/channels.json 核实频道和主播昵称:

  • 自有频道:Anibon Official(@anibonofficial)
  • 主要主播:Boat / Pu Boat(ปู่โบ๊ต / PhuBoat / โบ๊ต)

继续前,确保字幕稿中的说话人归属映射到 own_channel 昵称。

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

下载字幕稿,并创建 <workspace>/chunks/chunk_*.xml。

重要

检查损坏情况:如果字幕稿来自本地 Whisper 转录(或音频时长 ≥2h),请检查末尾条目是否存在重复循环。如果发现损坏(匹配率 >0.5),加载 whisper-corruption-recovery 技能,拆分损坏的尾部片段,重新运行该片段,并去重合并,然后再进行分块。

3. 清理字幕稿(可选)

在信号检测前,规范化 Thai-Whisper 产生的乱码英语。脚本位于 cleaning-auto-transcripts 技能中;请从时间戳生成器技能根目录解析该技能路径。

python3 -X utf8 ../cleaning-auto-transcripts/scripts/clean_garbled_english.py --chunks ~/youtube_<id>_workspace/chunks/
3.5 下载并对齐 LiveChat(可选,但建议)

为每个子 Agent 提供对应分块的观众聊天内容,使其能同时根据主播发言和聊天内容判断情境与情绪。此步骤需要网络;如果某个 VOD 没有 live_chat 字幕,请跳过此步骤,并仅根据字幕稿判断情绪。

# 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/

输出:livechat/livechat_chunk_NN.txt(每个字幕稿分块对应一个文件)和 livechat/livechat_index.json。如果 yt-dlp 报告没有 live_chat 字幕,请继续 — 子 Agent 将改用仅基于字幕稿的方式。

编辑过的直播 / 缺少 .live_chat.json 时的回退方案(视觉聊天提取)

当直播流在 YouTube Studio 中被剪辑或编辑后,YouTube 会永久删除 .live_chat.json 聊天回放轨道,yt-dlp 也会报告没有可用的聊天字幕。

为了避免丢失高关注时刻的观众互动背景,可从 anibon-livechat-analysis 运行 extract_visual_livechat.py,对特定高峰片段(例如表情包刷屏、高额 SuperChat 捐赠、观众问答或高潮反应)中的烧录聊天覆盖层进行 OCR:

# 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/

这会为目标片段窗口生成 <workspace>/livechat/livechat_chunk_NN.txt,直接供 analyze_555.py(步骤 3.7)和子 Agent 提示词生成使用,无需下载完整视频。

3.6 提取活动与摄像头时间线(可选,但建议执行)

捕获屏幕上的游戏 / 网页浏览内容,以及 Pu Boat 是否出现在摄像头画面中和其是否处于离开状态,以消除语音与动作之间的偏差错误。

# 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/"

输出:<workspace>/activity/activity_chunk_NN.txt,其中包含屏幕上的游戏 / 应用状态、摄像头画面中是否有人,以及肢体表情,供注入子 Agent。

3.7 检测泰式笑声 / 表情包脉冲(可选,但建议执行)

此步骤位于 align_live_chat.py 之后。泰国观众会用 555... / xD / ฮา / ขำ 标记笑声。短时间内集中刷屏即代表出现表情包 / 笑声高峰。当自动转录无法听到主播实际发笑时,这是唯一可靠的笑声代理指标。它会为每个片段生成情绪判定 + 泰语语气指导,子 Agent 提示词在编写带有情绪色彩的描述时必须参考这些信息。

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

输出:mood_555.json — 字典,片段 → {density, n_markers, n_messages, peak_windows, pulse, mood, verdict, tone}。tone 字段包含与片段情绪类别匹配的泰语指导(tone + 建议的 verbs)。判定结果:

  • *_PULSE — 脉冲通过加权评分 → 情绪导向的指导。MEME_PULSE(好笑)、CUTE_CUNNY_PULSE(可爱)、SHOCK_HYPE_PULSE(兴奋)、DRAMA_NEWS_PULSE(新闻 / 戏剧性内容)、ANGRY_OUTRAGE_PULSE(愤怒吐槽)等。
  • HOT / WARM — 有一些标记,但没有形成脉冲 → 轻松玩笑 / 活跃语气指导
  • QUIET — 聊天较少,没有形成脉冲 → 中性,可自由选择动词

说明

情绪是指导,而非规则。 tone/verbs 提示会告诉子 Agent 聊天呈现了哪种氛围;AI 仍会根据具体情境自行选择首个动词。只有当 PULSE 片段的时间戳描述把当时的氛围写得平淡时,validate_mood.py(步骤 11.5)才会提醒人工审核。

表情字典参考:参阅 references/anibon_emoji_dictionary.md,了解完整的频道专属表情映射(:_CunnyBoat:、:_MonkeyBoat:、:_Nerd:、:_shutup:、:_Grind:、:_Ripfish:、:_noname:、:_What:、:_WOW:、:_Ahh:、:_Meh:、:_MoneyBoat:、:_Tahaan:、:_KonDee:、:_NeoSlim:、:_Slim:、:_BoatSOM:),以及 YouTube 全局表情对应的情绪脉冲权重和安全屏蔽触发条件。

如果某个片段被标记为 MEME_PULSE,但子 Agent 为其写出的首个动词平淡且偏事实陈述,validate_mood.py(步骤 11.5)就会将这种语气不匹配标出以供审核。

4. 分析(预检)

快速汇总片段类别、缺失项和字节大小。注意:在 Windows 上,使用 -X utf8 以避免控制台出现 UnicodeEncodeError。

python3 -X utf8 scripts/anibon-analyzer.py ~/youtube_<id>_workspace/
5. 检测信号 → 匹配知识文件

对所有分块进行 TF-IDF 分析。将关键词与每个分块对应的知识文件进行匹配。

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

输出:signals.json — 每个分块的加权信号:matched_files(包含 df/weight)、weighted_matched_files(按排名排列)、best_file、primary_topic、confidence。

路径约定: knowledge.json 中每个 best_file/matched_files 路径都相对于 timestamper 技能根目录。references/stream/*.md = timestamper 本地文件;../anibon-world-identity/references/*.md = world-identity 技能文件;../reference/* = 顶层数据目录中的文件。所有路径都从 timestamper 根目录解析,绝不要从当前工作目录解析。

稀有度 = 核心思想:detect_signals.py 根据逆文档频率(log(N/df))为每个匹配的关键词加权。高频词(df 高)是日常用语填充词,得分为 0——会被忽略。低频词(罕见词)才是有辨识度的核心思想。只有在 confidence 明确时才将 best_file 交给子 Agent;否则省略该知识文件。

5.5 加载 World-Identity(如果信号匹配到游戏参考资料)

触发条件: signals.json 中的 best_file/weighted_matched_files 解析到 ../anibon-world-identity/references/ 下的文件(即截止日期之后的游戏/角色名称)。这些名称是子 Agent 最容易产生幻觉的内容。

操作: 加载 anibon-world-identity 技能。它会依次使用 references/INDEX.md → 缓存的故事参考资料 → 参考 SRT → 网络搜索备用方案,构建经过验证的泰语音素 → 英文名称映射表。首先初始化其游戏数据库:

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"

将解析出的名称映射表注入第 7 步的子 Agent 提示词中(针对信号匹配到这些文件的任何分块),以便 [Story] 标记使用规范名称,而非根据音素猜测。若流内容涵盖截止日期之前的知名内容,则跳过。

6. 检测主题边界(可选)

适用于主题转换明显的长流。运行:

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

如果边界看起来杂乱,可根据 signals.json 手动识别:寻找 matched_files 发生变化的分块(例如,游戏→Genshin→FGO)。记录时间戳,以便在第 9 步使用 --break-at。

7. 派生子 Agent(并行)

将分块划分为每组 4–5 个(每组约 20–25 分钟)。每组使用一个 anibon-chunk-timestamper。

运行 build_subagent_prompts.py 来准备输入文件:

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

此操作会生成:

  • <workspace>/prompts_by_chunk/chunk_NN.txt:每个分块对应的提示词文件(约 15–25KB,每个文件都保证小于 view_file 的 46KB 查看上限,以防分块内容被截断)。
  • <workspace>/prompts/group_NN.txt:列出分块文件 URI 和元数据的组清单。

重要

严格并发分批(建议使用 4–6 个子 Agent):为避免 API 429 RESOURCE_EXHAUSTED 速率限制(尤其是组清单达到约 50–100KB 时,可能导致滚动 TPM 耗尽),请按受控批次启动子 Agent,每轮启动 4–6 个(最多 8 个)。等待每批完成后,才能启动下一批。

使用 Flash 模型层级:调用 invoke_subagent 为分块时间戳工具指定 Model: "flash",以最大限度提高速度并留出速率限制余量。

按分块顺序读取:指示子 Agent 通过 view_file 按顺序读取其分配的 file://<workspace>/prompts_by_chunk/chunk_NN.txt 文件,以确保完整读取 100% 的文本且不被截断。

调用模式(每组一个):

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
..."""
)

每个分块提示词包含:

  • 分块 XML/对话行
  • 来自 signals.json 的检测信号(best_file + primary_topic + confidence + 排序后的 weighted_matched_files)
  • 每个分块的 LiveChat 日志(livechat/livechat_chunk_NN.txt)
  • 每个分块的屏幕活动日志(activity/activity_chunk_NN.txt)
  • 来自 mood_555.json 的每个分块的情绪判断 + 语气指南

**关键:**Agent 会按顺序读取其所在组的分块,并跳过续接分块。 不要自行加入主题摘要,只注入信号数据。

每个 anibon-chunk-timestamper 会返回纯文本时间戳行(通常每组 2–4 行)。

重要

视觉 AI 与生成式工具的依据核实: 当主播测试或评价视觉 AI 生成器(例如文生图、视频生成或创意编辑工具)时,需区分:

  1. 主播实际提出的提示词。
  2. AI 模型实际在屏幕上生成的内容(或其失败/拒绝生成的情况)。
  3. 主播带有喜剧、政治或夸张色彩的讽刺吐槽。 绝不能把讽刺吐槽(例如 "กลายเป็นคอมมิวนิสต์"、"เหมือนสลิ่ม"、"หลอนเป็นเปรต")当成生成图像的字面描述。始终使用 [Reaction],并明确标注吐槽者(例如 ปู่โบ๊ตเหวอ TH-AI เจนเป็นสาวไซเบอร์ยืนคู่ ครม. ไม่รู้จัก Jane Doe แซวยังกะรัฐบาลจีน)。

重要

时间戳起点与随口类比防护:

  1. 起点定位:始终将时间戳起点定位在讨论主题的开场句。切勿在关键专有名词已经说出后才从句中间开始标记(避免观众点击后错过上下文)。
  2. 随口类比规则:切勿将一两句话的随口类比或讽刺吐槽(例如把某个节目的预算拿来和 Frieren 比较)提升为主要时间戳标题。始终描述核心主题(例如 One Punch Man S3 与 J.C.Staff 的风波),并将随口比较放在括号中。
8. 合并时间戳

将每个子 Agent 的输出写入各自的文件(例如 chunk_001.txt、chunk_002.txt)。然后合并并按时间顺序排序:

python3 scripts/merge_timestamps.py ~/youtube_<id>_workspace/chunk_*.txt \
  -o ~/youtube_<id>_workspace/all_timestamps.txt
8.5. 审查遗漏(摘要器运行前的必做步骤)

此步骤用于强制执行不留遗漏铁律。对合并后的列表运行该工具;如果退出码非零,则针对每个被标记的分块启动补全 Agent(工具会打印需要重新处理的 chunk_NN),并在第 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 将音频切片发送至 Whisper.cpp 并清理乱码笔记(依据事实)

子 Agent 必须只输出定位标记(- "token" @ HH:MM:SS (chunk_NN))。分两个不同阶段执行:

步骤 8.6a:先运行 whisper.cpp(编排器音频基准真值)
  1. 从分块时间戳输出中提取所有辨音备注,并保存到 <workspace>/garbled_notes_raw/candidates.txt。
  2. 运行 whisper_dispatcher.py,对时间戳进行聚类、即时切分音频,并通过本地 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

这会生成 <workspace>/garbled_notes.json,其中包含:

  • google_sentence:来自 raw_transcript.th-orig.json3 的确切上下文句子窗口。
  • whisper_segment:与时间对齐的声学句子片段,来自 whisper.cpp(-oj)。
  • correct:规范目标(自动从词典解析,或由子 Agent 设置)。

提示

切片失败恢复(单个集群): 如果任何集群切片失败(例如因临时流套接字超时而退出,状态码为 187):

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

将转录文本更新到 garbled_notes.json,然后再传给 anibon-garbled-notes。

步骤 8.6b:稍后调用 anibon-garbled-notes 子 Agent(基准真值对齐与词典同步)

将 whisper_dispatcher.py 得到的声学转录结果传给 anibon-garbled-notes 子 Agent:

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."""
)

子 Agent 会更新 <workspace>/garbled_notes.json 并执行:

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

警告

避免在 macOS 上使用 --cookies-from-browser:提取浏览器 Cookie 会触发 GUI Keychain 密码验证提示,导致无头/命令行后台 Agent 任务挂起。使用 --extractor-args "youtube:player_client=android",无需凭据即可干净地绕过 YouTube SABR HTTP 403 错误。

注意

防级联基准真值检查:始终对照 raw_transcript.th-orig.json3 核查候选辨音备注。如果候选项在泰语文本中包含多词游戏/动漫标题(例如 Yuri on Ice、Chaos Zero Nightmare、Where Winds Meet、SLAPP),则这是过度激进的清理规则造成的伪影。切勿将清理器伪影保存到 garbled_replacements.json。

输出:

  • ~/youtube_<id>_workspace/garbled_notes.json — 所有候选项(garbled、google_sentence、whisper_segment、correct、chunk、ts、cluster_span)
  • resources/garbled_replacements.json — 在根目录与技能资源之间自动同步的规范分组映射(TargetWord: [patterns...])

词典为共享资源(resource_path() 会逐级向上查找到插件根目录),因此今后的每次直播都会自动加载新规则。确实无法解析的专有名词会保留 correct: null,以供人工确认。

9. 最终组装 — anibon-summarizer(替代 wrap + pack)

将完整排序后的 all_timestamps.txt 传给 anibon-summarizer 子 Agent。它会去除跨分块重复项,按宏观主题连贯性分组(避免因 3,500 字节上限而过度拆分),筛选必要的时间戳(长直播约 40–60 个时间戳),编写简朴风格的分段标题,并生成最终 Markdown。

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

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

子 Agent 会直接输出完整的 output.md。将其保存到 ~/youtube_<id>_workspace/output.md。

说明

pack_timestamps.py 仍可用于离线/脚本运行,或在明确要求按单条评论字节数拆分时使用。在标准会话中,应优先采用宏观主题分组并筛选必要的时间戳,以保持主题连贯性。如果明确要求限制单条评论的字节数:

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. 验证章节
python3 scripts/check_sections.py ~/youtube_<id>_workspace/output.md

检查项:每个章节的字节数上限 ✅,不含 ASR 错乱模式。

11. 验证主题连贯性(可选)

将时间戳中的游戏名称与 signals.json 中的真实数据进行交叉比对。标记虚构的名称或不同部分之间的主题串扰。

python3 scripts/validate_part_coherence.py ~/youtube_<id>_workspace/output.md \
  --signals ~/youtube_<id>_workspace/signals.json \
  --chunks ~/youtube_<id>_workspace/chunks/
11.5 验证情绪与聊天脉冲(可选)

作为 analyze_555.py 的配套工具。为每个时间戳标注其分块的情绪 + 泰语语气指导(AI 可选用的动词)。仅供指导——不会拒绝任何动词;AI 可以自由发挥动词创意。仅生成报告;退出码为 0。用于检查 PULSE 时段的时间戳是否确实体现了分块的能量。

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. 目录编目、归档与词典同步(系列结束协议)

生成并验证 output.md 后(或多部分系列运行结束后):

  1. 同步错乱笔记:

    • 收集并汇总所有部分中分块时间戳子 Agent 发现的 GARBLED_NOTES:。
    • 将其写入 resources/garbled_replacements.json 的 "mappings" 键下(data["mappings"]),并保留 version、description、note 这些头部元数据键。
    • 同步插件根目录和随附副本中的文件(resources/garbled_replacements.json 和 skills/anibon-timestamper/resources/garbled_replacements.json)。
    • 将更新后的词典提交并推送到 GitHub(anibon-stream-synthesis.git)。
  2. 导入 timestamp_workspace:

    • **必需子技能:**使用 backing-up-timestamps。
    • 运行 python3 -X utf8 import_workspace.py ~/youtube_<id>_workspace(或批量处理 ~/youtube_*_workspace)。
    • 自动归档结构化转录文本(transcripts/transcript_<id>.jsonl.gz)、复制 extras/<id>/、自动重建搜索索引(python3 -m anibon_search build),并在 by_video_id/timestamp_<id>.md 和 README.md 中建立条目链接。
    • 将 timestamp_workspace 提交并推送到 GitHub(ZenitHTH/timestamp-workspace.git)。
  3. 归档原始工作区:

    • 将已验证的目录移至 ~/youtube_workspaces/backed_up/。
    • 更新 metadata/catalog.json 中的 workspace_path。

输出格式

单个 .md 文件,包含 ═══ 分节块:

# Title | ANIBON

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

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

辅助脚本

脚本用途
scripts/prepare_video.py下载 + 清理 + 分块
scripts/dump_chunk_text.py从 XML 分块中导出格式整洁的文本,供子 Agent 使用
scripts/anibon-analyzer.py预检:缺口、类别、字节大小
scripts/detect_signals.pyTF-IDF 信号 + 知识文件匹配
scripts/detect_boundaries.py检测主题边界(在步骤 9 中提供给 --topic-json)
scripts/align_live_chat.py将 LiveChat 事件流切分为逐转录分块日志(步骤 3.5)
scripts/analyze_555.py从对齐后的 LiveChat 中检测泰式笑声/梗脉冲 → 逐分块情绪判定(步骤 3.7)
scripts/validate_mood.py验证带情绪的时间戳是否遵循 mood_555 判定(步骤 11.5)
../anibon-livechat-analysis/scripts/parse_live_chat.py将 .live_chat.json 解析为事件流(步骤 3.5)
../anibon-livechat-analysis/scripts/extract_visual_livechat.py当 .live_chat.json 缺失时,通过 Gemini 视觉代理提取烧录在画面上的 LiveChat(步骤 3.5)
scripts/merge_timestamps.py合并 + 排序子 Agent 输出
scripts/process_chunks_local.py通过 LM Studio / llama.cpp OpenAI 端点运行本地 LLM,顺序处理分块
scripts/audit_gaps.py缺口审计(NO GAPS 规则)+ 缺口→分块映射(步骤 8.5)
scripts/pack_timestamps.py按字节限制打包片段(支持 --break-at、--topic-json)
scripts/check_sections.py验证字节上限 + ASR 错乱文本
scripts/validate_part_coherence.py交叉核对游戏名称与信号
scripts/validate_tags.py验证时间戳标签词汇
../cleaning-auto-transcripts/scripts/clean_garbled_english.py规范化 Thai-Whisper 错乱英文(步骤 3)
../cleaning-auto-transcripts/scripts/clean_transcript.py清理原始 json3(由 prepare_video 调用)
../anibon-world-identity/scripts/fetch_story_ref.py获取/缓存故事梗概(需用户同意进行网页搜索)
../anibon-world-identity/scripts/align_ref_timeline.py将参考 SRT 时间戳与分块对齐
../anibon-world-identity/scripts/fetch_fgo_db.py、fetch_ygo_db.py构建卡牌数据库(World Identity)

铁律

  • 使用指定的 Agent — 第 7 步必须按每个分块调用 invoke_subagent("anibon-chunk-timestamper")。第 8.6 步必须调用 invoke_subagent("anibon-garbled-notes")。第 9 步必须调用 invoke_subagent("anibon-summarizer")。绝不能用通用 Task/自身 Agent 替代。
  • 严格分批调用子 Agent(建议每批 4–6 个) — 按每批 4–6 个子 Agent 进行受控处理(使用 Model: "flash" 时最多 8 个),等待完成后再开始下一批。处理繁重提示词任务时,绝不能同时启动 10 个或更多子 Agent。
  • 分块任务使用 FLASH 模型层级 — 为分块时间戳子 Agent 使用 Model: "flash",以确保快速执行并避免 API 速率限制。
  • 禁止启发式/正则表达式回退 — 子 Agent 遇到错误或速率限制时,绝不能回退到启发式文本生成脚本。所有时间戳都必须由真实运行的 anibon-chunk-timestamper 子 Agent 读取真实的转录 XML 和 LiveChat 日志后生成。
  • 使用 detect_signals.py — 仅使用 TF-IDF。不得临时使用 grep/内联扫描。
  • 不要自行读取分块 — XML 由子 Agent 读取。将 signals.json 数据注入提示词。
  • 单个文件 — 使用包含 ═══ 分节块的单个 .md 文件。不要创建 part1.md。
  • 不得有时间间隙 — 时间戳之间最多间隔 10 分钟,除非已确认期间无内容。
  • 拆分开场部分 — 开场部分超过 10 分钟时,按 3–5 分钟的子主题里程碑拆分。
  • 禁止临时时间戳 — 只能通过子 Agent 流程 → merge_timestamps.py → anibon-summarizer 生成。
  • 阅读两边内容 — 子 Agent 在编写任何时间戳之前,必须读取整个转录分块,以及对应的 LiveChat 日志(如有)。情境和情绪必须同时依据对话与聊天内容,绝不能只依据 primary_topic。
  • 遵从情绪判定 — 存在 mood_555.json 时,将各分块的 tone 指引(情绪 + 建议动词)注入子 Agent 提示词。AI 可自行选择首个动词,但不得将聊天中欢笑/亢奋的高潮平淡化成冷静客观的动词。
  • 扭蛋内容禁止剧透 — 时间戳描述中绝不能透露主播抽卡是成功还是失败。重点应放在期待感、当期卡池/角色以及聊天互动上。
  • 18+/RULE 34 语气完整性 — 不得将成人同人图或 Rule 34 评论轻描淡写地归入通用搞笑标签([Reaction] ฮา...)。应使用 [Talk],给出成熟、直接且准确的概述。
  • 专有名词与游戏标题完整性 — 处理乱码笔记(第 8.6 步)时,绝不能将有效的外部游戏标题(例如 MARVEL Tōkon: Fighting Souls、Alien: Isolation、TMNT: The Last Ronin)、品牌名或常见英文短语(例如 where we meet)识别为噪声模式。未经确认的专有名词必须保留为 correct: null,交由人工审核,不得强行转换成泛化的泰语词汇。
  • 每个时间戳都必须包含专有名词 — 每个时间戳都必须写出具体专有名词(例如 Wuthering Waves、Zelda、น้องเนเน่ AGT、Bleach)。绝不能使用含糊的代词(“这个游戏”“那个人”“这家公司”)。摘要器绝不能删掉专有名词;应删减形容词或情绪填充语。

评论

支持 Markdown