用 FunASR 出带时间戳的原始结果,再用标点模型恢复标点,合并后字幕整体比人声提前约 200ms,切分点落在字中间,播放器里明显抢拍。
一开始怀疑是「音频起始有 200ms 静音被 VAD 裁掉,时间轴没补偿」,查了一圈,方向不对。
真正麻烦的地方在于,几个原因的现象几乎一样。标点模型返回的是字符级偏移,与词级时间戳混用。少数情况下是合并时按标点结果重排了句子但没有回填原始时间。
不容易想到的是,帧长 10ms 与 20ms 混用,累计误差正好差一倍。
动手时先打印相邻两条结果的起止时间看是否连续
python -c "import json;d=json.load(open('asr.json'));print([(s['start'],s['end']) for s in d[:5]])"
随后用 ffmpeg 截取偏差点前后各 1 秒人耳复核
ffmpeg -ss 00:03:10 -t 2 -i ep.wav -ac 1 check.wav
再往下把标点结果按原字符索引映射回词级时间
python align.py --punct punct.json --asr asr.json --mode char-index
等前面都确认过,再统一帧长按 10ms 取整后再导出 srt
python to_srt.py --round 10 --shift 0.2
恢复的判定其实很直接。导出字幕在播放器里与人声同步,前后各抽 10 句起止时间与波形起点误差在 50ms 内。
容易忽略的是,时间戳对齐的关键是保留原始字符索引,任何一次按句子重排都会丢掉索引,事后只能靠听感调偏移量,很难批量修。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
