Install
openclaw skills install @shengbinxu/bilibili-subtitle专业对话稿生成助手。把视频/音频转成【带说话人标注】的专业对话稿——区分谁说的、Clean Verbatim 可读性重排、金句高亮、公众号可直接粘贴。支持 B 站视频作为输入源(下载音频、查询信息),适用于访谈、播客、会议等多人对话场景。
openclaw skills install @shengbinxu/bilibili-subtitle把视频/音频变成专业对话稿(transcript)——能区分"谁说的"、读着不累、可高亮金句、可直接粘进公众号。产物是对话稿(给人读),不是字幕(subtitles,给画面看)——两者标准不同,见下文"可读性重排"。
当前支持的输入源:B 站视频(下载音频 → ASR 说话人分离 → 对话稿)。音频下载通过 scripts/run.js 执行;语音转写通过 scripts/asr_transcribe.py 执行。
每次对话第一次调用本 Skill 时,必须首先完成环境准备。
路径固定为:~/.workbuddy/skills/bilibili-subtitle/scripts/run.js
将此路径记为 RUN_JS。
node "$RUN_JS" init
run.js init 依次完成:Python 3 检查 → requests 安装。
解析输出 JSON:
ok: true → 环境就绪,从返回的 skill_dir 字段提取值记为 SKILL_DIR,静默完成,进入对应子流程ok: false → 按错误码映射表输出对应话术(见错误处理章节)按顺序判断,命中即停止:
第一关:用户消息中包含 B站链接(b23.tv、bilibili.com)或 BVID(BV 开头的字符串),且包含「下载音频」「下载」「音频」等词?
→ 是 → 【下载音频意图】执行前置流程 + 下载流程
第二关:包含 B站链接/BVID,想了解视频基本信息(如「这个视频多长」「什么内容」),但不需要下载? → 是 → 【信息查询意图】执行信息查询流程(无需环境准备)
第三关:用户想要「字幕」「转写」「文字稿」「对话稿」「逐字稿」「谁说的」「区分说话人」,或明确是访谈/播客/会议要区分发言人? → 是 → 【对话稿生成意图】执行对话稿生成流程(说话人分离)
第四关(兜底):用户含糊表达(如「帮我下载这个视频」),但未提供链接? → 是 → 询问:「请提供B站视频链接或BVID~」
从用户消息中提取 BVID,支持以下格式:
https://www.bilibili.com/video/BV1DLdcB4ErM → BV1DLdcB4ErMhttps://b23.tv/NkqyQTP → 需先请求展开,再从重定向URL中提取 BVIDBV1DLdcB4ErM → 直接使用短链接展开方法:用 curl 跟随重定向,从最终 URL 中提取 BV 开头的字符串。
前提:前置流程已完成环境准备。
node "$RUN_JS" download --bvid "<BVID>" --output "<输出路径>"
解析输出 JSON:
ok: true → 下载成功,提取 audioPath、title、duration、fileSizeMB,进入展示结果步骤ok: false → 按错误码映射表输出✅ 音频下载完成!
📹 视频:{title}({duration}分{durationSec}秒)
🎵 文件大小:{fileSizeMB} MB
📁 保存路径:{audioPath}
无需环境准备,直接调用。
node "$RUN_JS" info --bvid "<BVID>"
解析输出 JSON:
ok: true → 查询成功,提取 title、duration、durationText、cover、desc、ownerok: false → 按错误码映射表输出📹 视频信息
标题:{title}
UP主:{owner}
时长:{durationText}
封面:{cover}
简介:{desc}
目标:把音频转成带说话人标注的对话稿,能区分"谁说的",而不是一段流水账。 方案:腾讯云 ASR「录音文件识别 + 说话人分离」(模式1)+ LLM 身份映射。
B站视频(BVID)
│ [run.js download] 下载 m4a(48kHz 立体声,几百 MB)
▼
audio.m4a
│ [asr_transcribe.py transcode] ffmpeg 转 16k 单声道 mp3
▼
audio_16k.mp3(几十~一百 MB)
│ [asr_transcribe.py run] 上传 COS → CreateRecTask(说话人分离) → 轮询
▼
<结果目录>/asr_result_detail.json ← 带 SpeakerId + 时间戳的结构化片段(核心产出)
<结果目录>/.asr_task_id ← 任务 ID,保存失败时可凭它重新拉取救数据
│ [asr_transcribe.py build] 按说话人聚合成轮次 + 身份映射
▼
dialogue.txt / dialogue.html ← 最终交付(带【姓名】+时间戳)
常见失败点:转码参数错 → COS 上传失败 → CreateRecTask 非法参数 → 保存时 SDK 对象序列化失败(见下方"经验教训")。
x/web-interface/view 查 subtitle.list 确认;为空则必须走本流程。TENCENT_SECRET_ID / TENCENT_SECRET_KEY / TENCENT_COS_BUCKET / TENCENT_COS_REGION 传入,或复制 asr_config.example.json 为 asr_config.json 填写(该文件不得提交到公共仓库)。pip install tencentcloud-sdk-python cos-python-sdk-v5 # Python SDK
# 系统需安装 ffmpeg(转码用)
复用【下载音频流程】拿到 m4a 文件。
腾讯云 16k_zh 引擎要求 16kHz 单声道,B站音频通常是 48kHz 立体声,必须转码:
python3 scripts/asr_transcribe.py transcode --input "<下载的m4a>" --output "<输出.mp3>"
export TENCENT_SECRET_ID="..."
export TENCENT_SECRET_KEY="..."
export TENCENT_COS_BUCKET="your-bucket-appid"
export TENCENT_COS_REGION="ap-shanghai"
python3 scripts/asr_transcribe.py run --input "<16k单声道.mp3>" --output-dir "<结果目录>"
脚本内部:上传到 COS → 生成预签名 URL → CreateRecTask(16k_zh + SpeakerDiarization=1 + SpeakerNumber=0)→ 轮询 DescribeTaskStatus → 保存结果。
输出 asr_result_full.json(含 ResultDetail,带 speaker ID 和时间戳)。
保存失败?用
rescue救数据(不要重跑识别) 若run因保存/序列化逻辑出错导致结果存空(典型症状:asr_result_detail.json缺失或ResultDetail为空、最终稿无说话人标记),不要重跑run(浪费额度+3~5分钟)。直接凭已生成的.asr_task_id重新拉取:bash python3 scripts/asr_transcribe.py rescue --output-dir "<结果目录>"该命令读取
.asr_task_id调DescribeTaskStatus重新取结果并正确保存(用_serialize()序列化),秒级免费。
腾讯云返回的说话人是数字 ID(SPEAKER_0/1/...),不知道谁是谁。由 assistant(LLM)读取全文语义完成映射:
不要只凭开场独白下结论,分两步交叉验证:
--speaker-map "0:鲁豫,1:张泉灵"(ID 顺序按 ASR 输出,不同视频不同)。用 build 子命令把 ResultDetail(按说话人聚合成轮次)一键生成对话稿:
python3 scripts/asr_transcribe.py build \
--input-dir "<结果目录>" \
--speaker-map "0:鲁豫,1:张泉灵" \
--out-name dialogue
--speaker-map 的映射来自 Step 4 的 LLM 判定(不同视频不同)<结果目录>/dialogue.txt(纯文本,带【姓名】+时间戳)与 dialogue.html(配色对话稿,配色可在 build_dialogue.py 里改 NAME_COLOR)FinalSentence(已合并标点、无词间空格,直接可读);SliceSentence 带词间空格仅适合对齐,不要直接出稿。连续同说话人片段自动并为一轮。若未提供 --speaker-map,输出用 Speaker0/Speaker1 占位,后续再替换。
build 直接出的 dialogue.txt 是 Strict Verbatim(全保留口语词+碎片)——每个 ASR 句是一轮,满屏"呃/嗯/然后"和一两句的碎片,读着极累。访谈/播客逐字稿给人读时,行业事实标准是 Clean Verbatim(智能逐字)。完整工作流是两遍:
dialogue.txt (Strict Verbatim, 含 P0 修正)
│ 第一遍:P0 最小修正(修错别字/标点/专名,保留口语词)
▼
dialogue_clean.txt
│ 第二遍:Clean Verbatim 可读性重排
│ - 删无意义填充词/口误/false starts
│ - 合并连续同讲者碎片为段落
│ - 保留情绪感叹、故事细节、对话节奏
▼
dialogue_clean_v2.txt + dialogue_clean_v2.html
为什么分两遍:第一遍保"准确"(不丢任何词,方便回查原文/跳回听音);第二遍保"可读"(去口语噪音、合并碎片)。两版都留着,用户按需取用。
Clean Verbatim 操作手册(已实战验证):
并行执行模板(19 块 / 7 agent,50 轮每块):
dialogue_clean.txt 按 50 轮/块切到 proofread/v2_chunks/(项目目录,别用 /tmp,见教训 6)。chunk_XX.txt、写 proofread/v2_clean/clean_XX.txt,prompt 含上述操作手册 + 一个 before/after 示例(如"逼单"段)。dialogue_clean_v2.txt;校验字符数合并前后一致(防丢内容)。build_clean_v2_html.py 生成配色 HTML(配色常量 NAME_COLOR/NAME_BORDER 可换主题,如蔷薇紫、红蓝等)。给对话稿里"对成长有启发"的金句加划线高亮,让稿子从"记录"变成"可反复回看的成长素材"。
工作流(已实战验证):
dialogue_clean_v2.txt 按 240 段/块切到 proofread/highlight_chunks/。[{speaker, time, quote, reason}],quote 必须 15-80 字、逐字照抄原文。build_clean_v2_html.py:加 load_quotes() + apply_highlights(),在段落 HTML 里给金句子串包 <mark style="background-color:#e8d8f0;...">(纯色底,公众号安全)。坑:agent 挑金句时倾向改字"润色",导致高亮文字和稿子对不上。必须逐字校验,把 agent 返回的 quote 当作"待校验"而非"已确认"。
专业依据(对外解释用):GoTranscript / Rev / 广电总局字幕规范 均将 Clean Verbatim 列为访谈、播客、学术逐字稿标准;字幕(subtitles,限行/无标点/去口气词)≠ 逐字稿(transcript,有标点/分段/分讲者),给人读的产物用逐字稿标准。
dialogue.txt 修掉明显错分、补标点断句。style="..."(见教训 8),否则 <style> 块和 CSS 类会被公众号剥光。用 mdnice(rose 蔷薇紫等主题)渲染公众号文章可自动内联;自己 build 的 HTML 要在脚本里写死内联样式。SDK 返回的是对象,不是字符串(最隐蔽的坑)
腾讯云 ASR DescribeTaskStatus 的 Result / ResultDetail 会被 SDK 反序列化为 SentenceDetail 对象列表,而不是 JSON 字符串。任何"当作字符串 f.write() / json.dump()"的代码都会静默失败(ResultDetail 存空、Result 存错),最终得到无说话人标记的流水账——本次首轮正是因此翻车。
✅ 正确做法:用每个对象的 _serialize() 转 dict 再序列化(脚本 to_jsonable() 已封装)。
保存失败别重跑识别,用 taskId 救数据
ASR 任务结果在服务端保留一段时间。若保存/解析逻辑出错,不要重跑整个 run(浪费一次识别额度 + 3-5 分钟),直接拿 .asr_task_id 里存的任务 ID 调 DescribeTaskStatus 重新拉取即可,秒级且免费。本次靠这招把 5951 个分离片段完整救回。
CreateRecTask 没有 ResponseFormat 参数
传了会报 UnknownParameter 导致建任务失败。别加这个字段。
ResTextFormat 用 1,不要用 3
3(词级时间戳)会把 ResultDetail 炸成几千个词级碎片(本次 5951 段),且 Result 字段类型在该格式下不稳定;1(句级+标点)段数少、每段是完整句子、干净可读,最适合做对话稿。
免费额度当月有效,Key 用后轮换 新用户 10 小时录音文件识别额度自领取当月有效,过期作废(当天用正好);SecretKey 一旦暴露建议立即禁用重置。
精校中间产物必须落盘到项目目录,绝不用 /tmp
长访谈(如 192 分钟)做"分块 LLM 精校"时,常把 dialogue.txt 切成 50 轮/块、逐块精校再合并。这些中间块(chunks)和精校块(clean)必须放在当前工作目录(如 proofread/chunks、proofread/clean),不能用 /tmp。本次实测:/tmp 会在会话/用户轮次之间被回收,已完成的 19 块精校稿(含多轮人工迭代)全部随 /tmp 清空丢失,只能重做。教训:凡是要跨多轮/多会话保留的中间产物,一律写项目目录;若已误用 /tmp,先 cp 到项目目录再继续。合并前务必校验总轮数(原文 933 轮),防止子任务漏轮——本次有一个 clean 块漏了 2 轮,靠 diff 说话人标签行 + 总轮数核对补回。
逐字稿级别(verbatim level)选错 = 读着累的根因 用户抱怨"断句太短、口语词费劲",本质不是识别差,而是稿子落在 Strict Verbatim(全保留 呃/嗯/碎片)。给人读的访谈/播客逐字稿,标准应是 Clean Verbatim(去填充词+合并同讲者碎片,保情绪/故事/对话感)。别把"保留口语词"做成 Strict——那是字幕/话语分析思路,不是逐字稿思路。先和用户校准力度(Clean Verbatim / 更轻 / 更重)与结构(合并成段 / 保留每轮),再全量跑,避免做重或做轻返工。
公众号编辑器只保留内联样式(CSS 类/渐变会被剥光)
自己 build 的 HTML 若用 <style> 块 + CSS 类(.turn、.s0、border-left 写在类里),粘进公众号后整块被剥,左侧色条、卡片底色、高亮全消失。本次对话稿粘贴后"左侧样式没了"正是此因。
✅ 正确做法:所有样式写成内联 style="...";高亮用纯色 background-color(公众号保留),别用 linear-gradient(会被剥);标签优先 <section>(公众号兼容好于 <div>)。mdnice 渲染的公众号文章能保留样式,就是因为它输出全内联。
金句高亮必须逐字校验,agent 会擅自改字 派 agent 挑金句时,它会倾向"润色"原文(改字、补字、跨段拼接),导致高亮文字和稿子对不上。本次 31 条里 2 条不匹配(agent 把"你情绪高涨的才能让他停留"改成了"我觉得在这个世界上…")。✅ 必须用脚本对每条 quote 在原文做精确子串匹配,不通过的从原文取真实句子替换,校验 100% 通过再生成 HTML。
| 坑 | 说明 |
|---|---|
| 引擎不支持指定人数 | 16k 引擎 SpeakerNumber 只能为 0(自动,最多20人),可能多分离出噪音 speaker,需后处理合并 |
| 只返回数字 ID | ASR 不知道真实身份,必须靠 LLM 语义映射 |
| 音频必须转码 | 48kHz 立体声 → 16kHz 单声道,否则引擎报错 |
| 音频需可 URL 访问 | 推荐 COS(同账号免外网流量);URL 方式 ≤5小时/≤1GB |
| 长音频耗时 | 3 小时音频约需 3-5 分钟识别,用后台任务 + 轮询 |
触发条件:脚本返回 ok: false
| error | 展示给用户 |
|---|---|
MISSING_BVID | 请提供B站视频链接或BVID~ |
DOWNLOAD_FAILED | 视频下载失败,可能是B站反爬限制,请稍后重试 |
INFO_FAILED | 获取视频信息失败,请确认BVID是否正确 |
PYTHON_VERSION_2 | 本 Skill 需要 Python 3,请安装后重试 |
INSTALL_FAILED | 依赖安装失败,请手动执行 pip3 install requests |
PYTHON_ERROR | 脚本执行异常,请稍后重试 |
MISSING_CONFIG | 缺少腾讯云配置,请设置 SecretId/SecretKey/COS Bucket 环境变量或填写 asr_config.json |
NO_FFMPEG | 未找到 ffmpeg,请先安装(转码音频需要) |
TRANSCODE_FAILED | 音频转码失败,请检查源文件是否损坏 |
ASR_FAILED | 语音识别任务未成功,可凭 taskId 复查或重试 |
| 网络超时/异常 | 服务暂时开小差了,稍后帮你重试 🔧 |
{xxx} 均为占位符,输出前必须用对应实际值替换,严禁带花括号原样发出;对应值为空则改用不含该占位符的话术。| 文件 | 路径 | 内容 |
|---|---|---|
| 配置 | scripts/config.json | 默认输出目录 |
| 音频输出 | <输出目录>/<BVID>.m4a | 下载的音频文件 |
| ASR 配置模板 | scripts/asr_config.example.json | 腾讯云凭证模板(复制为 asr_config.json 填写,勿提交公共仓库) |
| ASR 结果(全) | <结果目录>/asr_result_full.json | Result + ResultDetail 完整结果 |
| ASR 结果(片段) | <结果目录>/asr_result_detail.json | 核心产物:带 SpeakerId + 时间戳的片段列表,build 命令读它 |
| ASR 任务 ID | <结果目录>/.asr_task_id | 任务 ID,保存失败时可凭它重新拉取救数据 |
| 对话稿(文本) | <结果目录>/dialogue.txt | 带【姓名】+时间戳的纯文本对话稿 |
| 对话稿(HTML) | <结果目录>/dialogue.html | 配色对话稿(配色在 build 脚本里改) |