| name | bilibili-transcript |
| disable-model-invocation | true |
| description | 把哔哩哔哩直播回放(单 P 视频)转成时间线回顾(Recap)。输入 BV 号或视频 URL。 |
Bilibili Transcript
把哔哩哔哩直播回放转成按时间线组织、按主题分组的 Recap Markdown。
领域语言见 CONTEXT.md;形态决策见 docs/adr/。
前置
- Linux 一等支持;仓库根即 skill 根(本文件与代码同仓)
- 已 clone 本仓库,并按所选后端安装依赖(见 README)
- 宿主 agent 能在本仓库根目录执行命令、读写文件,并用自身 LLM 写 Recap
- 公开可下载的单 P 视频(无 cookie;大会员 / 地区限制 / 非公开内容不保证)
产物链
Video → Audio → Transcript → Recap
- prepare 脚本(确定性):下载音频 + ASR → Transcript(
transcript.json + meta.json)
- agent LLM(推理):读 Transcript 写 Recap
Transcript 是缓存层:同一 BV 已生成则跳过 ASR。重跑 Recap 时步骤 2 直接缓存命中,不重下载、不重转录。
步骤
0. 解析 Backend(首次必问)
后端三选一,禁止静默替用户决定、禁止自动降级:
| backend | 含义 | 依赖 extra | 费用 |
|---|
cpu | 本地 SenseVoice,CPU | cpu | 免费 |
rocm | 本地 SenseVoice,ROCm GPU | rocm | 免费 |
aliyun | 云端 Paraformer-v2 | aliyun + .env 凭证 | 按量 |
解析顺序:
- 若项目根已有
.bilibili-transcript.json 且含合法 backend → 采用之,向用户确认本次沿用(一句话即可)
- 否则在仓库根执行:
uv run bili-prepare --probe
根据 JSON(suggested、rocm_available、aliyun_ready 等)给出建议,询问用户选 cpu / rocm / aliyun。
3. 用户确认后写入项目根(该文件已 gitignore):
{
"backend": "cpu"
}
可用 shell 写入,例如:
printf '%s\n' '{"backend":"cpu"}' > .bilibili-transcript.json
- 后端不可用(如选
rocm 但 GPU 不可用、选 aliyun 缺凭证)→ 硬失败;向用户解释错误,征得同意后改配置/参数再跑,不要擅自换后端重试。
1. 跑 prepare(下载 + ASR)
在项目根目录同步执行(不要后台):
uv run bili-prepare <BV号或URL> --backend <cpu|rocm|aliyun> [--force]
- 已写入配置时可省略
--backend;推荐显式传入以便日志与用户预期一致
- 时长参考(约):16 分钟音频 rocm ~25s;同长 cpu 约 1 分钟量级;2h 音频 rocm 约 1–3 分钟、cpu 约 5 分钟、aliyun 约 5–10 分钟 → 长音频把命令超时放宽到 10–15 分钟
- 产物在
.cache/<BV>/:transcript.json(segments [{start, end, text}],秒)、meta.json(元信息 + ASR 统计)
- 失败即退出(exit ≠ 0,ASR 零段也视为失败);
--force 重下载并重跑 ASR
完成标准:exit 0,transcript.json 非空(≥1 段),meta.json 可读且含 backend、duration_s、title。
2. 读 Transcript 写 Recap(单次 LLM 调用)
读 .cache/<BV>/transcript.json 的全部 segments(整段喂入,不做 map-reduce)与 meta.json(title、uploader、duration_s)。
超长分支:转录文本超出上下文窗口时,按时间顺序切块,每块按同一契约归纳,再按时间合并;任何块不得整块丢弃。
Recap Markdown 契约:
- 标题:
# {视频标题}
- 主题段:
## {主题} (start-end),时间戳 MM:SS,时间戳只出现在段级标题,条目内不加
- 段内正文:用简洁的一段话总结该主题内容(2-4 行,一句起)
- 主题从内容归纳,不机械切片;段落按时间线排序,同一主题聚在一段
- 段数约 1 段/2-3 分钟(2h 视频 15-30 段)
示例:
# 老木匠直播20260808(弹幕版)
## 开场闲聊 (00:00-05:00)
开场打招呼说早上变冷了,和弹幕聊了会儿天气,气氛轻松。
## 木工话题 (05:00-30:00)
开始讲今天的木工活:准备做一张桌子,先交代木料选择和尺寸规划。
完成标准(全部可检查):
- 覆盖到结尾:最后一段的区间终点 ≥
duration_s - 60,尾段不得遗漏
- 每段带
MM:SS-MM:SS 区间,与段内内容的时间范围一致;段内正文无时间戳
- 段数约 1 段/2-3 分钟;主题从内容归纳(可辨认的素材,不是机械切片)
3. 交付
写 recaps/{标题}.md(recaps/ 在项目根,不存在则创建;标题取 meta.json 的 title,把 /\:*?"<>| 替换为 _,去掉首尾空白)。
告知用户:Recap 路径 + ASR 统计(backend、耗时、成本,取自 meta.json)。
边界
- 单视频(单 P UGC 直播回放);不处理合集、多 P
- 不做说话人分离;下载无 cookie(仅公开视频)
- 大会员 / 登录墙 / 地区限制内容不保证可下载
- 一次只处理一个 BV
- 首发不支持 NVIDIA CUDA 一等后端(本地 GPU 仅 rocm)