video-transcript
GitHub视频/播客逐字稿提取工具。支持多平台链接解析与本地FunASR转录,具备说话人分离、口语润色及PDF排版功能。默认直接处理链接,按平台特性交付逐字稿或优化版文案。
Trigger Scenarios
Install
npx skills add Backtthefuture/video-transcript --skill video-transcript -g -y
SKILL.md
Frontmatter
{
"name": "video-transcript",
"metadata": {
"display-name": "视频文案提取"
},
"description": "视频\/播客逐字稿提取 Skill。使用 FunASR 在本机转录(无需 API Key);视频用 SenseVoice-Small,播客\/访谈用 paraformer + CAM++ 区分主持人与嘉宾。支持微信视频号、 抖音、小红书、B站、YouTube、小宇宙及本地音视频。用户说“出文案\/提取文案\/出逐字稿\/ 转文字\/视频字幕\/主持稿\/播客转文字\/区分说话人”,粘贴上述平台链接,或提供本地媒体文件时使用。 视频号默认在对话中交付口语逐字稿;“文字PDF”生成同稿文字版;“截图PDF”加入关键帧, 正文不得改写成导读。其他视频平台默认交付整理优化版;播客交付说话人区块版。用户明确说 “只下载\/保存MP4”时只下载。ASR 在本机运行,但链接解析需要联网;视频号首次使用需在本机 扫码登录腾讯元宝。\n",
"allowed-tools": "Read, Write, Edit, Bash, Glob, Grep"
}
视频文案提取专家
输入链接 → 解析一次 → 直链提音频(+模型预热并行) → FunASR → 机器预整理 → 按平台交付 视频号:读 skills/weixin-layout.md,默认对话交口语稿;文字PDF / 截图PDF 用 Kami 羊皮纸长文 B站/抖音/小红书/YouTube:LLM 只出 patch → 主持稿/整理优化版 播客:说话人区块成品,直接交付
阶段 0 · 定位 skill 根目录(第一件事)
if [ -z "${VT_HOME:-}" ]; then
VT_HOME="$(
for d in "$HOME/.workbuddy/skills/video-transcript" \
"$HOME/.agents/skills/video-transcript" \
"$HOME/.Codex/skills/video-transcript" \
"$HOME/.codex/skills/video-transcript" \
"$HOME/.claude/skills/video-transcript" \
"$(pwd)/.Codex/skills/video-transcript" \
"$(pwd)/.claude/skills/video-transcript" \
"$(pwd)/skills/video-transcript" \
"$HOME/.Codex/plugins/video-transcript/video-transcript" \
"$HOME/.claude/plugins/video-transcript/video-transcript"; do
[ -f "$d/SKILL.md" ] && echo "$d" && break
done
)"
fi
export VT_HOME
echo "VT_HOME=$VT_HOME"
如果输出为空,让用户给出路径后 export VT_HOME=<路径>。
之后所有命令都通过 "$VT_HOME/scripts/transcript.py",不要硬编码路径。
优先用带 funasr 的解释器:
VT_PY="${VT_PY:-$HOME/.workbuddy/binaries/python/envs/default/bin/python}"
[ -x "$VT_PY" ] || VT_PY="/opt/anaconda3/bin/python3.12"
[ -x "$VT_PY" ] || VT_PY="python3"
阶段 1 · 意图分流(贴链接 = 直接转录,不问)
默认规则:用户贴视频/播客链接 → 直接进入转录,不询问。
| 用户行为 | 处理 |
|---|---|
| 贴微信视频号链接,无其他说明 | 默认逐字稿:直接转录,对话里交口语稿,不排 PDF。读 skills/weixin-layout.md |
| 贴视频号 + 「逐字稿」/「逐字稿版本」 | 同上 |
| 贴视频号 + 「文字PDF」/「文字版本」 | 同一份口语稿 → Kami 羊皮纸文字PDF |
| 贴视频号 + 「截图PDF」/「截图版本」 | 同一份口语稿 + 视频关键帧 → Kami 羊皮纸截图PDF;转录加 --keep-video |
| 贴 B站/抖音/小红书/YouTube 链接,无其他说明 | 直接转录,不问,走整理优化版 |
| 贴播客/音频链接(小宇宙/喜马拉雅/Apple Podcasts) | 直接转录,自动带说话人分离 |
| 贴链接 + 说「文案/逐字稿/主持稿/转文字」 | 直接转录;若是视频号,按上一行对应模式 |
| 明确说「只下载」「保存MP4」「不用转录」 | 走 video-download |
| 只说「处理视频」但没附链接 | 问用户要链接 |
平台支持分三档,不确定的链接直接试,不要预先劝退:
| 档位 | 平台 | 说明 |
|---|---|---|
| 专门解析 | B站(含 b23.tv)、抖音、小红书、YouTube、微信视频号、小宇宙单集 | 最稳 |
| 播客链路 | 小宇宙单集、喜马拉雅单集、Apple Podcasts | 自动说话人分离 |
| yt-dlp 兜底 | 微博、知乎、西瓜视频、AcFun 等 | 能跑,默认走视频链路;要区分说话人加 --speakers |
| 不支持 | Spotify(DRM)、快手 | 脚本给出原因+替代做法 |
常见误贴:小宇宙节目主页(/podcast/)和喜马拉雅专辑页(/album/)都不是单集页,
脚本会明确提示改用单集链接 —— 把提示原样转达给用户,别自己瞎猜别的原因。
仅下载时定位 video-download 后跑 download_video.py "<URL>" --json,不要再进入转录。
视频号三种交付(先读这个)
识别到 weixin.qq.com/sph 或 channels.weixin.qq.com 时,不要走阶段 4 的「整理优化版 / make_optimized.py」。先读 skills/weixin-layout.md,按三种模式交付。
| 用户怎么写 | 交付 |
|---|---|
| 什么都不写,或「逐字稿」「逐字稿版本」 | 默认。 整理过的口语逐字稿,发在对话里。不排 PDF |
| 「文字PDF」(旧称「文字版本」) | 同一份口语稿,Kami 羊皮纸纯文字 PDF。文件名 = 官方标题 |
| 「截图PDF」(旧称「截图版本」) | 同一份口语稿 + 视频关键帧。文件名 = 官方标题 |
三种共用一份口语正文:补标点、分说话人、改对专有名词。禁止把正文改写成导读 / 概述 / Takeaways。封面最多 2–4 句原话金句。
B 站 / 抖音 / 小红书 / YouTube / 播客不受影响,继续走后面的原流程。
阶段 2 · 依赖体检(首次/可疑时)
已验证过且环境没变化的,跳过体检。首次/换电脑/报错才跑:
"$VT_PY" "$VT_HOME/scripts/transcript.py" --doctor
有 ✗ 项就跑 bash "$VT_HOME/install.sh"。核心依赖没有 ✗ 就可以处理本地文件和其他平台。
--doctor 只检查依赖和视频号认证,不会冒充真实链路验收。需要验证视频号时,用一个可公开测试的分享链接:
"$VT_PY" "$VT_HOME/scripts/transcript.py" --doctor-live "<公开视频号链接>"
阶段 3 · 一条命令跑完下载+转录+预整理
用户给了链接就立刻跑,不要先单独 probe,不要再调一次 download:
"$VT_PY" "$VT_HOME/scripts/transcript.py" "<URL或本地路径>"
视频号「截图PDF」必须留视频文件才能抽帧,加 --keep-video:
"$VT_PY" "$VT_HOME/scripts/transcript.py" "<视频号链接>" --keep-video
可选:
--force忽略同 URL 缓存--keep-video额外保存完整 MP4(默认只提音频;截图PDF 必加)--no-daemon不用常驻模型(默认会自动拉起 FunASR daemon)
脚本会自动:
- 缓存 — 同一 URL 已有预整理稿则秒回;视频号去 skills/weixin-layout.md,其他平台进入阶段 4
- 解析一次 — 视频号优先 HTTP(元宝 Cookie),失败才开一次浏览器;B 站/抖音/小红书探测时缓存直链
- 并行 — 后台预热 FunASR daemon,同时 ffmpeg 直链提 16k wav(不下完整 MP4)
- 转录 — 长视频按 ≤5 分钟切块;有 daemon 则顺序流式写出,无 daemon 则最多 2 进程并行
- 预整理 — 机器完成切段/合并碎句/候选标题,写出
*_预整理.md+*_polish_brief.json
stderr 会先打 📊 评估表。立刻复述给用户(标题/时长/预估耗时),不要等全部跑完。
长视频还会写 $VT_HOME/outputs/.partial/<hash>/chunk_XX.md 和 progress.json。
转录还没结束时,你可以读已经完成的 chunk,边转边改标题/纠错,最后再合并进一份 patch。
完成后 stderr 有 ----- VT_OUTPUTS ----- 一行 JSON,里面有:
preorganized_path— 预整理稿(你的主输入)polish_brief_path— 增量润色任务书transcript_path— 原始逐字稿(对照存档;B站等平台不要在对话里全文展示)video_path— 仅--keep-video时有,截图PDF 用它抽帧stream_dir— 分块流式目录
若是微信视频号:到这里停,去 skills/weixin-layout.md。 不要进入阶段 4,不要跑 make_optimized.py。
视频号失败时按错误码处理,不要把隐私同意误说成技术鉴权:
WECHAT_AUTH_REQUIRED/WECHAT_AUTH_EXPIRED:让用户在本机运行sph_resolver.py --login,扫码后重试。WECHAT_PARSE_EMPTY/WECHAT_PARSE_TOKEN_MISSING:登录已通过,但该分享链接没有得到可用解析结果;说明可能是链接、内容权限或页面接口变化。WECHAT_FEED_FAILED/WECHAT_STREAM_EMPTY:已经进入视频详情阶段,但没有媒体流;可请用户上传本地 MP4/MOV 继续。- 不要自动改用或请求授权使用
public-worker。该服务当前需要额外服务器凭据,不是公开兜底。
阶段 4 · 你(agent)必须做的事:只出 patch,不要重写全文
本阶段只给 B 站 / 抖音 / 小红书 / YouTube 等非视频号视频。视频号看 skills/weixin-layout.md。
核心交付仍是「整理优化版 / 主持稿」。但机器已经做完分段和合并,禁止再把全文抄进 content.json,也禁止在对话里把同一篇稿子重写两遍。
正确流程(必须按此执行)
- 读
preorganized_path全文(以文件为准,stdout 可能截断) - 读
polish_brief_path - 只写一份很小的
patch.json,字段:title: 可选,润色后的大标题headings: 与章节顺序对齐的语义化小标题(可只改需要改的)fixes:[{"from":"原词","to":"修正词","confidence":"high|low"}](high会自动替换全文对应词)paragraph_edits: 仅当整段结构都要改时才给{"section":1,"para":0,"replace":"..."}
- 渲染(一次即可):
"$VT_PY" "$VT_HOME/scripts/make_optimized.py" \
--from-md "<preorganized_path>" \
--patch "<patch.json>" \
--filename "YYYY-MM-DD_标题30字内_整理优化版" \
--output-dir "$VT_HOME/outputs"
- 读取生成的
*_整理优化版.md,在对话里完整输出整理优化版全文(纯 Markdown,不要用代码块包裹) - 需要预览时
present_files只传整理优化版.html(第一位) +.md - 末尾附一行落盘路径
章节很多时的并行润色
polish_brief.json 里 sections 超过 4 个时:
- 按 4 章一组拆成多个小 patch(只要
headings切片 + 该段fixes/paragraph_edits) - 可以并行想、但最后必须合成一个
patch.json再跑make_optimized.py - 仍然不要输出多份全文
绝对不要做
- ❌ 把原始无标点逐字稿贴进对话
- ❌
--dump-template再把全文填进content.json(旧流程已废弃) - ❌ 只展示前几段、总结或改写观点
- ❌ 缓存命中后还重新下载/转录(除非用户说「重跑」/
--force)
缓存命中
脚本打印 [OK] 缓存命中 时:直接用已有 预整理.md 做 patch → 渲染整理优化版。用户明确要求重跑才加 --force。
播客/说话人分离模式
触发:小宇宙 episode 链接自动启用;其他输入(本地音频/任意 URL)加 --speakers 强制启用。
# 小宇宙链接:自动说话人分离,无需额外参数
"$VT_PY" "$VT_HOME/scripts/transcript.py" "https://www.xiaoyuzhoufm.com/episode/xxxx"
# 本地音频/其他来源:强制说话人分离,可手动指定人名
"$VT_PY" "$VT_HOME/scripts/transcript.py" 访谈.m4a --speakers --host 张三 --guest 李四
# 只重跑后处理(调版式/改人名),复用已有转录,不重跑 ASR、不重新下载
"$VT_PY" "$VT_HOME/scripts/transcript.py" <同一输入> --reformat --host 张三 --guest 李四
版式不满意/人名认错时用 --reformat,不要用 --force。 --force 会连十几分钟的 ASR 一起重跑;
--reformat 复用 outputs/.partial/<hash>/transcription.json,1 小时单集约 1 分钟出新版。
小宇宙以外的播客平台(喜马拉雅/Apple Podcasts)没有音频直链,自动用 yt-dlp 取音频,
拿不到 Shownotes,所以说话人会回退成「说话人 A/B」,想要真名就手动传 --host / --guest。
产物:*_逐字稿.md(说话人区块,成品)、*_逐字稿.srt(带说话人前缀、句级时间轴,可直接压字幕)、
*_outputs.json、.partial/<hash>/transcription.json(原始转录,--reformat 的输入)。
转录期间每 30 秒打一行 [转录中] 已跑 x 分,约 y%,预计还需 z 分。
进度是按音频时长估的,不是真实完成度;转录本身是一次不可中断的推理,
中途失败只能重跑(不切块是有意的:CAM++ 的说话人编号只在单次推理内一致,切块会让同一个人在不同块里换编号)。
ASR 一落盘就删掉临时 wav(1 小时单集约 115MB);要留音频排查加 --keep-audio。
与视频链路的区别:
| 视频链路 | 播客链路 | |
|---|---|---|
| 引擎 | SenseVoice-Small(快,~6x 实时) | paraformer + CAM++(慢,约音频时长 25%,1 小时单集约 15 分钟) |
| 说话人 | 无 | 自动分离 + 主持人/嘉宾映射 |
| 输出 | *_预整理.md(需 agent patch 润色) |
*_逐字稿.md(成品,直接交付,不走 patch 流程)+ *_逐字稿.srt |
| 首次模型 | SenseVoice 234M | paraformer/CAM++/VAD/punc 约 1GB |
自动化处理:小宇宙页 __NEXT_DATA__ 解析标题/音频直链/Shownotes → 从 Shownotes 提取主持人/嘉宾姓名(取不到回退「说话人 A/B」) → 半截词缝合 → ct-punc 补标点 → 语义分段 → 通用 AI 术语纠错。
输出版式(说话人区块):
## 说话人
- **主持人** 曲凯:约 30% 时长
- **嘉宾** 孟繁青:约 70% 时长
## 逐字稿
### 00:22 – 00:30 主持人 · 曲凯
因为这块也很热嘛,所以今天很开心请到…
播客专属词表扩展:在 $VT_HOME/.podcast_glossary.json 写 [["错误词","修正词"], ...],会叠加在内置通用 AI 术语表之上。
agent 拿到播客 *_逐字稿.md 后:直接在对话里输出全文(或按用户要求摘要),不要再跑 make_optimized.py。
阶段 5 · 异常处理
| 场景 | 处理 |
|---|---|
--doctor 报缺依赖 |
bash "$VT_HOME/install.sh" |
| funasr 未安装 | pip install funasr torchaudio |
| 首次运行联网失败 | 首次需下载 SenseVoice-Small(约 234M) |
| 播客模式首次很慢 | 首次自动下载 paraformer/CAM++/VAD/punc 模型(约 1GB),之后走本地缓存 |
| 播客版式/人名要改 | 用 --reformat(秒级),别用 --force(会重跑 ASR) |
| 播客转录中途中断 | 只能重跑,ASR 不支持续跑(切块会打乱说话人编号);已完成的单集看 .partial/<hash>/transcription.json |
| 某节目专有名词老是错 | 写 $VT_HOME/.podcast_glossary.json: [["错词","对词"]],优先于内置词表 |
| 小宇宙解析失败 | 页面结构变化;可先下载音频再 --speakers 转本地文件 |
| 抖音图文笔记 | 提示仅支持视频 |
| 平台前端改版 | 看 $VT_HOME/FALLBACK.md |
| 视频号缺登录态 | "$VT_PY" "$VT_HOME/scripts/sph_resolver.py" --login |
WECHAT_AUTH_REQUIRED / WECHAT_AUTH_EXPIRED |
在本机运行 sph_resolver.py --login,扫码后重试 |
WECHAT_PARSE_EMPTY / WECHAT_STREAM_EMPTY |
登录不等于链接可解析;保留错误码,可让用户上传本地 MP4/MOV |
| 视频号公共 Worker 401 / 1042 | 不再作为公开兜底;使用 yuanbao-login |
| 要保留 MP4 | 给脚本加 --keep-video,或走 video-download |
视频号解析默认 yuanbao-login。sph_resolver.py 先抽 Cookie 走 HTTP,失败才开一次浏览器。
"$VT_PY" "$VT_HOME/scripts/sph_resolver.py" --check
"$VT_PY" "$VT_HOME/scripts/sph_resolver.py" --login
"$VT_PY" "$VT_HOME/scripts/asr_daemon.py" --status
命令行选项
| 参数 | 说明 |
|---|---|
input |
视频 URL 或本地路径 |
--title |
覆盖标题 |
--no-save |
不落盘 |
--output-dir |
改保存路径 |
--doctor |
体检 |
--doctor-live <视频号链接> |
在体检基础上验证认证→解析→媒体流,不下载/转录 |
--force / --no-cache |
忽略同 URL 缓存 |
--keep-video |
额外保存 MP4(视频号截图PDF 必加) |
--no-daemon |
不使用常驻模型 |
--speakers |
强制说话人分离模式(小宇宙链接自动启用) |
--host / --guest |
说话人分离模式手动指定主持人/嘉宾姓名 |
--reformat |
复用已有转录只重跑后处理(调版式/改人名,不重跑 ASR) |
--keep-audio |
播客模式转录后保留临时 wav(默认清理) |
Notes
- 视频引擎 FunASR SenseVoice-Small:中文 CER 7.81%,模型 234M,CPU 约 6x 实时
- 播客引擎 paraformer-zh + fsmn-vad + ct-punc + CAM++:带说话人分离,约 0.15x 实时
- 视频号不再 probe+download 各解析一遍;默认也不下完整视频
- FunASR daemon 常驻后,后续任务跳过 15~30s 模型加载;空闲 30 分钟自动退出
- 时间戳是段落级,用于章节定位
- 预估耗时:
时长/8 + 15s(直链音频 + 已预热模型) - 热词:
$VT_HOME/.env里FUNASR_HOTWORD=词1 词2 - ASR 转录在本地运行,不需要 API Key;链接解析和首次模型下载需要联网
- 微信视频号三种交付见 skills/weixin-layout.md:默认对话逐字稿;文字PDF / 截图PDF 用 Kami 羊皮纸长文;文件名用视频原标题
Version History
-
b02f1e1
Current 2026-09-02 21:28
新增视频号三种交付模式(口语稿、文字PDF、截图PDF),重写为中文说明,强化微信环境安装与健康检查。
- db38d02 2026-08-27 09:11


