错字集中在人名和术语时,先别急着重录,也别立刻铺一张大词表。通常先做一次成本对照:把错字按时间戳落回原音,看它是集中在某几个说话人、某几段噪声明显的录音,还是全篇均匀出现;再挑同一段文本、换一套更好的采集条件重录一次,比对错字的数量和位置。如果重录后错字明显减少,瓶颈在音源,优先改采集;如果同一个错词在多个说话人、多次录音里稳定复现,说明模型对这个词的先验不足,用词表统一替换更划算。两条路不是二选一,多数情况下是先改能改的采集条件,再把剩下的错词沉淀成词表。
先做一遍成本对照:把错字按时间戳回听原音,确认它是否集中在少数说话人、少数词或某类噪声段落。若重录同一段内容后错字明显减少,优先改采集;若同一错词在多个说话人、多次录音中稳定复现,就把它写进词表做统一替换。词表要带上下文限制条件,避免误替换,并放到项目里可版本管理的位置,而不是留在个人本地目录。
回听原音,标出错字集中的时间段
先把转写结果按带时间戳的格式导出,很多转写工具都支持逐句带时间戳的文本或字幕文件。没有时间戳就无法判断错字是散落还是聚集,这一步不能省。把错词逐个回听,固定记录三项:出错时间点、对应的说话人、该段落的背景噪声情况(安静室内、键盘声、空调底噪、多人抢话、远处回声等)。
# 假设逐句导出为 TSV:起始时间 说话人 文本
grep -nE '张宏|失焦|微服' transcript.tsv
# 再把命中行按起始时间排序,观察是否聚成几段
sort -k1,1 transcript.tsv | grep -E '张宏|失焦|微服'判断口径可以先用定性标准:错字只落在两三个说话人身上,先查这几个人是不是离麦更远、语速更快或咬字更松;错字落在某几段时间里,先查那几段的噪声;如果每个说话人、每个时间段都有,而且错词各不相同,多半是通用识别能力问题,不是单点音源问题,这时候做词表的收益会更明显。
检查录音端的采集条件:距离、增益、有无回声
跟着时间戳回到那几段录音,检查三个采集条件。
- 麦克风距离:超过一臂的长距离拾音,会让高频辅音先衰减,人名这种短音节最容易糊掉。可以先量一下实际距离,再决定是否换近讲麦或加领夹麦。
- 是否出现削波:用 ffmpeg 看整轨峰值,文件本身不会说谎。若峰值贴近满刻度,先降增益重录,不要在后期硬修。
- 环境噪声类型:稳态底噪(空调、风扇、投影仪)可以靠近距离录音拉开信噪比;突发噪声(键盘、关门、桌椅拖拽)通常只能换时间段或换房间,后期降噪很难补回人名。
ffmpeg -i take01.wav -af volumedetect -f null -
# 关注输出里的 max_volume,贴近 0 dB 说明该段很可能已经削波
# 再看 mean_volume 与 max_volume 的差距,差距过大通常意味着增益设置不稳回声靠回听判断:尾音有拖尾、像是在空房间说话,混响会把人名的辅音抹掉,这类段落重录的收益往往大于做词表。需要结合环境确认的是,同一支麦克风在不同房间的表现可能差很多,别用一次录音的结论覆盖所有场景。
挑同一段内容用更好的条件重录一次做对照
不要整体重录,先挑一段做对照。选一段包含最多错词的 30 到 60 秒文本,用更好的条件重录:离麦更近、增益调到不削波、关掉空调或换到安静房间。一次只改一个变量,比如只改距离,或者只关噪声源,否则无法判断是哪个条件在起作用。
- 同一段文本:以句为单位编号,保证两版能逐句对齐,这是对照有意义的前提。
- 两种音源:文件名里带上条件,例如 take01_orig.wav 与 take01_close.wav,不要用“新版”“改后”这类含糊命名。
- 错字数量与位置:逐句记录错词,以及它错在句子的第几个词,位置信息比数量更能说明问题。
# 通用对照表,建议与音频放在同一目录的 notes 里
句子编号 原文 原音源转写 重录音源转写
S01 张泓 张红 张泓
S02 微服务治理 微服治理 微服务治理这里只看方向,不看具体比例。重录版的人名和术语错字如果从“几乎每句都有”变成“偶尔出现”,采集就是主要瓶颈;如果两版错在同一个词、同一个位置,说明改采集没有解决它,词表是更稳的做法。对照做完再决定投入方向,比凭感觉换设备省事。
把反复出错的词整理成替换词表
词表至少要有三列:原词,即转写输出里实际出现的错字;目标词,即正确写法;上下文限制条件,即什么情况下才允许替换。限制条件是关键——人名和术语经常与常用词同音,无条件全局替换会把本来正确的地方改错。
// glossary/replacements.json
{
"rules": [
{"from": "张红", "to": "张泓", "speaker": "张三"},
{"from": "微服", "to": "微服务", "pattern": "微服(?=架构|调用|治理|拆分)"},
{"from": "某内部代号", "to": "正确写法", "note": "确认无歧义后再启用"}
]
}带上下文的规则用正则先行断言表达,只在后面跟着“架构、调用、治理”这类词时才替换;不带上下文的规则只用于确实不会歧义的专有名词,并且最好限定说话人。脚本先跑 dry-run 输出命中列表,人工确认后再落盘,避免一次性把稿子改花。
import json, re
rules = json.load(open("glossary/replacements.json", encoding="utf-8"))["rules"]
def apply(text, speaker=None):
for r in rules:
if r.get("speaker") and r["speaker"] != speaker:
continue
if r.get("pattern"):
text = re.sub(r["pattern"], r["to"], text)
else:
text = text.replace(r["from"], r["to"])
return text
# 先对一份稿子跑一遍,把每条规则的命中句子打印出来核对替换建议只对最终稿做一次,不要在每轮校对里反复叠加,否则规则冲突后很难回溯是哪条改的。每条规则后面记一行来源,例如首次出现的时间戳和说话人,以后判断这条规则是否还成立就有依据。
决定后续同类录音是先改采集还是先做词表
一条可直接复用的判断线是看错字是否与音源条件相关。用上一步对照的结论:重录后错字减少或位置改变,属于该改采集;重录后同一个错词在同一个位置复现,并且在多个说话人、多个场次都出现,属于该做词表。
- 改采集:适用于单人近讲、访谈、固定工位的会议。动作是固定麦克风距离、把增益调到不出现削波、关掉稳态噪声源,再重录一次验证。
- 做词表:适用于音频已经无法重录,或者人名与术语本身是固定集合(客户名单、产品名、内部代号)。动作是把反复错的原词、目标词、上下文条件写进词表,统一跑一次替换。
- 两者都要:人名靠词表兜底,采集条件负责把整体听感拉回来。通常是先改善还来得及改的采集条件,再把剩余错词沉淀进词表。
验证方式是下一次同类录音转写后,重新跑一遍第一步的时间戳统计,看同一批错词是否还出现、是否还在同一位置。词表文件的留存位置建议放在与录音项目同级的 glossary/ 目录下并纳入版本管理,例如 glossary/replacements.json 与 glossary/terms.tsv,规则的新增、启用和停用都留记录,不要只放在某个人的本地目录里,否则换人接手时词表就丢了。风险边界也在这里:词表越长,误替换概率越高,每条带上下文的规则都要能解释为什么不会误伤;某条规则长期没有再次命中,可以先停用,不必直接删除。