一、这篇教程解决什么问题
做字幕的人常卡在同一步:文字转出来了,时间轴还得手工对。拖进度条、听一句、敲一个时间点,返工一次就得重听一遍。
这篇教程走一条可复现的动线:用阿里云百炼 CLI 合成一段语音(或直接用你手上的录音),转写拿到词级毫秒时间戳,再用词与词之间的静音间隔切出字幕条,产出一份可以直接用的 SRT 文件。
二、环境准备
| 项目 | 说明 |
|---|---|
| 命令行工具 | bl(阿里云百炼 CLI) |
| API Key | 在控制台密钥管理页创建,地域选华北2(北京),创建后完整复制保存 |
| 命令文档与音色/模型清单 | 见阿里云百炼 CLI(bl)与阿里云百炼首页 |
| 素材 | 一段音频;本教程先用合成音频演示,也可直接换成自己的录音 |
三、第一步:合成一段待转写语音
如果你已经有录音,可以跳过这一步,直接看第四步。
bl speech synthesize--text"今天下午三点在第二会议室开选题会,记得带上周的数据报表。"--voicelongcheng_v3--out通知.wav用合成音频做第一次练习的好处是:原文已知,转写结果可以逐字对照,出现差异时能立刻判断是识别问题还是输出约定。
四、第二步:转写,拿到词级时间戳
bl speech recognize--url通知.wav--languagezh--out通知.json--url接受本地文件路径,也接受音频 URL。
转写全文:
今天下午3点在第二会议室开选题会,记得带上周的数据报表。
与原文对照,唯一差异是"三点"变成"3点"。这属于 ASR 的数字规范化输出,不是识别错误,处理方式见 FAQ Q4。
返回的时间结构分三层:
| 层级 | 本轮返回 | 用途 |
|---|---|---|
| 全文 | 整段文本 | 校对、纪要正文 |
| 句级 | 1 段,160–4440ms | 粗粒度打点 |
| 词级 | 16 个词,每词带起止毫秒 | 字幕 cue 边界 |
词级时间戳节选:
| 词 | 起(ms) | 止(ms) |
|---|---|---|
| 今天 | 160 | 400 |
| 下午 | 400 | 680 |
| 3 | 680 | 840 |
| …… | …… | …… |
| 会 | 2480 | 2640 |
| 记得 | 2920 | 3200 |
| 报表 | 4160 | 4440 |
注意"会"与"记得"之间:2640 到 2920,空了280 毫秒,其余相邻词间隔为 0。这 280ms 就是原文逗号处的自然停顿,也是下一步切分的依据。
五、第三步:用静音间隔切分字幕条
切分规则:
- 顺序遍历词级数组,计算相邻词间隔
下一个词的起 - 当前词的止 - 间隔 > 阈值(本教程取250ms)→ 在此断开
- 间隔 ≤ 阈值 → 并入当前字幕条
- 每条字幕的起止时间取该条首词的"起"与末词的"止"
不要按标点切:词级输出不带标点,16 个词拼起来是"今天下午3点在第二会议室开选题会记得带上周的数据报表",逗号不在里面。
也不要按句段切:本教程第二轮用三句话素材(“第一个议题是季度复盘。第二个议题,下月选题排期。散会前记得提交周报。”)实测,三句被并成了一个句段,标点还被规范化(“复盘。第二"变成"复盘,第二”)。句段数不等于原句数。
阈值怎么定见 FAQ Q3。
六、第四步:生成 SRT
按上面规则跑出的真实产物(本机文件原样):
1 00:00:00,160 --> 00:00:02,640 今天下午3点在第二会议室开选题会 2 00:00:02,920 --> 00:00:04,440 记得带上周的数据报表两条 cue 的断点正好落在原句逗号处:那里停顿 280ms,超过 250ms 阈值;其余位置间隔为 0,不会被切断。
SRT 时间格式为HH:MM:SS,mmm,由词级毫秒值换算而来,不做取整到秒。
七、参数表
| 命令 | 参数 | 本教程取值 | 说明 |
|---|---|---|---|
bl speech synthesize | --text | 会议通知一句 | 待合成文本 |
bl speech synthesize | --voice | longcheng_v3 | 音色 |
bl speech synthesize | --out | 通知.wav | 输出音频文件 |
bl speech recognize | --url | 通知.wav | 音频地址,支持本地路径 |
bl speech recognize | --language | zh | 语种 |
bl speech recognize | --out | 通知.json | 输出结构化结果 |
| 切分脚本 | 静音阈值 | 250ms | 自定义参数,需按素材校准 |
八、使用边界
- 数字规范化:三→3 这类转换是 ASR 的输出约定,不是错误;字幕文案要哪种写法自己定
- 词级无标点:按标点切条不成立;静音间隔切分是本教程方法,阈值需自校
- 句段会并段:多句素材的句段数不等于原句数,别拿句段当字幕条
- 说话人分离未实测:
--diarization本轮未跑(素材为单说话人),多人会议"谁说了什么"的效果不在本文结论内
补充一条前提:本教程素材为 TTS 合成音频,干净、单说话人。真实会议录音的底噪与重叠话会改变切分表现,请用自己的素材重跑并重新校准阈值。
九、常见问题(FAQ)
Q1:词级输出没有标点,字幕条怎么切?
不按标点切,按时间切。词级数组里每个词都带起止毫秒,相邻词的间隔就是切分信号:间隔大于阈值处断开,间隔为 0 处保持同一条。本教程 250ms 阈值下,280ms 的逗号停顿被切成断点,产出 2 条 cue。字幕文案本身由该条内的词文本拼接得到,需要标点的可以在后处理里按断点补。
Q2:为什么不能直接用句级时间戳做字幕?
句级粒度太粗,而且句段会并段。本轮一句话素材的句级只有 1 段(160–4440ms),三句话素材同样只返回 1 段。一条字幕横跨 4 秒以上,观众读不完;拿句段当字幕条必然切错。句级适合做章节打点,cue 边界应由词级推导。
Q3:静音阈值 250ms 怎么定?换个素材还适用吗?
250ms 是对本教程这段素材校准出来的,不是通用值。定阈值的做法是先统计素材全部相邻词间隔的分布:句内间隔通常接近 0,句间停顿通常几百毫秒,把阈值取在两者之间即可。语速快、停顿短的素材要调小,停顿多的口语和念稿要调大。换素材必须重新统计,直接沿用会漏切或碎切。
Q4:转写把"三点"写成"3点",是识别错了吗?
不是。这是数字规范化输出,口语数字在时间语境里被写成阿拉伯数字。字幕要口语写法就在后处理做逆映射;纪要、检索类用途保留阿拉伯数字反而好解析。需要与原文逐字比对时,先对两边做同一套规范化,否则差异统计会被这类转换污染。
Q5:多人会议的录音能用这套方法吗?
本教程未验证。素材是单说话人合成音频,--diarization(说话人分离)本轮没有跑,因此"谁说了什么"的效果、多说话人重叠时的切分表现都不在本文结论内。要做多人会议,请先用自己的素材实测说话人分离,再决定切分策略。
Q6:可以直接用自己的录音文件吗?
可以。bl speech recognize --url接受本地文件路径,跳过第三步的合成命令,直接转写自己的音频即可。真实录音的底噪、口音、重叠话会影响间隔分布,切分阈值需要重新校准。
Q7:生成的 SRT 时间为什么带三位毫秒?
SRT 标准时间格式是HH:MM:SS,mmm,逗号后是毫秒。词级时间戳本身就是毫秒值,直接换算即可,不建议四舍五入到秒——本教程两条 cue 的起点分别是 160ms 和 2920ms,取整到秒会让字幕与语音错位。
Q8:标点会被改动吗?
会。第二轮三句素材里,“复盘。第二"被规范化成"复盘,第二”。转写文本不能当作原文的可靠副本,需要精确标点的环节要么用原文,要么接受规范化结果并把规则记录下来。
十、小结
四步动线:合成(或准备录音)→bl speech recognize转写 → 按静音间隔切分 → 输出 SRT。这套方法里真正解决问题的是词级毫秒时间戳,它把"在哪切一刀"从人工听辨变成了可计算的间隔判断。
跑完建议先做一件事:把转写全文和原文逐字对一遍,看数字与标点差在哪。差异规律摸清了,后处理规则才写得准。模型与音色清单可在阿里云百炼首页查看。