方言字幕需要分别验证文本、时间和说话人
一段 128.847 秒的四川方言剧集音频,包含旁白、街边买蛋烘糕的对话、追逐和歌曲。对字幕或配音流水线来说,识别出文字只是第一步:漏掉整段对话、把时间标到错误位置、将同一个角色拆成多个 speaker,都会影响后续编辑。
本文比较九组 ASR 服务或配置,并讨论多源融合。它是一份针对该素材的工程案例,不是方言识别通用排行榜。本文修订时复核了对应工程的 Provider 和第 6 集 JSON 输出,没有重新调用收费 API,也没有据此宣称复现了原始听写实验。
先把比较对象和评判口径固定下来
测试 CLI 通过 Provider 接口调用服务,保留原始结果,再转换为统一分段结构:
from abc import ABC, abstractmethod
class ASRProvider(ABC):
name: str = "base"
input_type: str = "url"
@abstractmethod
def transcribe(self, audio_input: str, **kwargs) -> dict:
...
这只是接口,不是可直接运行的完整测试器。输入采样率、声道、音频预处理、服务地区、请求参数和后处理版本都应随运行记录保存。
| 对象 | 原评测记录的配置 | 复核时应注意 |
|---|---|---|
| 豆包 | asr_spk_semantic preset | 预设不是精确模型快照 |
| Fish Audio | 默认配置 | 默认模型可能变化 |
| Gemini | gemini-3.1-pro-preview | 提示词和返回格式影响输出 |
| OpenAI | 原稿标为 gpt-4o-transcribe-diarize | 原始 JSON 仅有全文,缺少本次调用参数,型号与格式需要请求日志确认 |
| Qwen | qwen3-asr-flash-filetrans | 本次 JSON 没有 speaker 字段 |
| 腾讯云 | 16k_zh | 说话人、情感及返回粒度由请求参数控制 |
| 讯飞 | 转写 API,speaker_number=0 | 保留具体接口版本与参数 |
| Paraformer | paraformer-v2 云服务 | 不等同于整套 FunASR 框架 |
| FunASR | paraformer-zh、fsmn-vad、ct-punc、cam++ | 框架、模型和运行设备分别记录 |
Gemini 3.1 Pro 于 2026 年 2 月发布,不能把通用推理榜单成绩作为音频转写能力的证据。Google 模型说明
返回文件中没有某字段,不等于模型没有该能力。 例如 gpt-4o-transcribe-diarize 不是 Whisper;官方接口支持带说话人标签的 diarized_json,长音频还需按接口要求配置分块。工程当前 Provider 已选择 diarized_json,但这不能追溯证明旧结果使用了相同配置。因此本次 OpenAI 文件只能作为旧文本输出观察,不能据它否定模型的说话人分离能力。OpenAI 模型说明
人工标注是基准,模型一致只能作为线索
原评测由熟悉方言的人员结合画面听写关键词。完整、独立的逐字转写与带说话人时间标注尚未随文章交付,因此不报告 WER、CER 或 DER。没有现成标准文本不意味着不能计算这些指标,而是需要先建立并复核标注。
其他模型输出一致可以辅助定位疑点,不能直接当成真值。进一步评测应在查看各模型答案前固定标注规则,包括方言异体字、数字归一化、语气词、歌唱和重叠说话如何计分。
原稿还记录了其他集数的试验,但这些素材是有针对性地选择的漏段样本。它们适合排查缺陷,不能证明总体表现排名稳定。
原始输出显示了哪些问题
豆包:局部文本可用,长空白仍要独立处理
第 6 集结果包含 16 个 utterance、6 个 speaker ID。这些区间总时长为 40.840 秒,占完整音频 31.7%。这个比例是“输出区间时长 / 整段音频时长”,其中分母还包含静音与音乐,不能称为语音内容覆盖率。
最明显的相邻分段空白是 22.880 秒至 68.190 秒,约 45.31 秒。其他结果在其中包含买蛋烘糕的多轮对话。这是需要回听检查的漏识候选,而不是把所有无输出区间都自动认定为丢失语音。
豆包结果包含情感和声音性别标签,但它们也是模型预测。例如短句的声音性别标签会变化,不能据此确定角色身份。全局 singing_mand 标记也不能定位每一个歌唱片段。
Fish:补充了对话文本,不能直接照搬时间轴
Fish 输出中能找到“蛋烘糕”和“半托半托”等片段,补充了豆包空白区间内的文字。原听写记录同时指出,它把“知青返乡”转成“自己返乡”,并非完整文本都正确。
原评测逐句对照发现后段时间偏移,例如“谢谢你啊”的分段与豆包相差数秒。模型间不一致说明至少需要进一步核对,精确误差仍应以音频人工边界为基准。不能因为前 17 秒接近,就把后续时间全部视为可信。
Gemini:文本错误与角色标注要分开评估
保存的 Gemini JSON 有 30 段、3 个 speaker ID,其中“我知青返乡”被写成“我四处犯相”,“蛋烘糕”对应了不相关文本。这样的输出不宜直接作为字幕底稿。
原评测认为其角色划分较连贯,但“刚好分成 3 人”并不能证明 diarization 最准确。文件中最大结束时间为 146.500 秒,超过音频总长约 17.65 秒;使用它来映射其他模型的 speaker 之前,必须先修复时间定位并核对说话人。标签种类较多也不代表情感识别更准确。
其余服务:输出结构与识别质量各有问题
| 对象 | 保存结果中的观察 | 对流水线的意义 |
|---|---|---|
| OpenAI | 仅保存全文、logprobs 与 usage;有多处方言词替换 | 先查请求型号与返回格式,再补测结构化能力 |
| Paraformer | 21 个句段、2 个 speaker ID;部分字时间近似均匀排列 | 需要声学边界核验,不能仅从现象断言服务内部使用插值 |
| FunASR | 38 个句段、4 个 speaker ID;出现“蛋黄糕”等替换 | 可本地复现并调参,离线不代表零计算和运维成本 |
| Qwen | 23 个句段,有情感、语言和字时间;没有 speaker 字段 | 这份输出不能承担角色区分;服务能力需另核配置 |
| 讯飞 | 7 个句段,speaker 全为 0 | 整句较长,但已有字时间,仍可研究重新分句 |
| 腾讯云 | 35 个分段、4 个 speaker ID;部分对话和歌曲混在长段中 | 可作时间候选,不能免除边界与角色复核 |
这些是本次文件的结构事实,不是当前各服务全部能力的列表。尤其不要把 FunASR 框架、某个 Paraformer 模型及某厂商云接口混为同一个实验条件。
关键词对比必须使用同一分母
原稿对豆包用 3/3,对其他服务用 5 个词作分母,排除了豆包未覆盖的两项,不能公平比较。修订后将五个检查项都纳入分母,漏识同样记为未命中。
下表只统计保存全文中的字符串出现,不等于句子语义正确率。“半托半托 / 半坨半坨”按原稿认可的两种写法计入;“半头半头”不计入。若后续人工标注改变异体字政策,应统一重算所有结果。
| 检查项 | 豆包 | Fish | FunASR | Gemini | OpenAI | Paraformer | Qwen | 讯飞 | 腾讯 |
|---|---|---|---|---|---|---|---|---|---|
| 知青返乡 | ✓ | — | — | — | — | — | — | ✓ | — |
| 蛋烘糕 | — | ✓ | — | — | — | — | ✓ | ✓ | ✓ |
| 半托半托 / 半坨半坨 | — | ✓ | — | — | — | ✓ | ✓ | ✓ | — |
| 老汉儿 | ✓ | ✓ | ✓ | ✓ | — | ✓ | — | — | — |
| 职工抓到要遭处分 | ✓ | — | — | — | — | — | — | — | — |
| 命中项数 | 3/5 | 3/5 | 1/5 | 1/5 | 0/5 | 2/5 | 2/5 | 3/5 | 1/5 |
例如 Gemini 的“老汉儿”出现在错误句子中,仍会被字符串统计命中。这正说明关键词命中只能诊断特定词,不能替代完整 CER/WER。原稿据此给出的全局星级与“方言之王”评价不再保留。
多源融合先保留证据,再生成候选
融合要解决的不是选出一个全能模型,而是把文字、时间和角色分别建立可追踪来源。
先找到需要补查的区间
无输出区间可能是静音、音乐或漏识。下面的函数仅计算分段覆盖的补集,后续仍需 VAD、其他输出和音频复核:
def find_gaps(utterances, total_ms, min_gap_ms=500):
if total_ms < 0 or min_gap_ms < 0:
raise ValueError("durations must be nonnegative")
intervals = []
for u in utterances:
start, end = u["start_ms"], u["end_ms"]
if not 0 <= start <= end <= total_ms:
raise ValueError("segment outside audio")
intervals.append((start, end))
gaps, prev_end = [], 0
for start, end in sorted(intervals):
if start - prev_end >= min_gap_ms:
gaps.append((prev_end, start))
prev_end = max(prev_end, end)
if total_ms - prev_end >= min_gap_ms:
gaps.append((prev_end, total_ms))
return gaps
原示例漏掉了尾部空白,也没有排序和范围检查。修订后的计算不会将超出音频长度的时间直接混入融合。
文本 Diff 只提出候选,不产生时间证据
现有工程把豆包与 Fish 的全文提交给 LLM,寻找主要结果缺少的语句。第 6 集 Diff 文件保存了 10 个候选及文本字符位置。字符偏移不是毫秒时间戳;仍需用音频上下文、顺序与其他服务的时间候选进行对齐。
单纯用“语义相似”覆盖原文也可能把两个不同句子合并。每个候选应保留原始文本、来源、匹配依据及人工修订状态;置信不足时留待审核,不强制填进最近时间窗。
当前保存的融合文件包含 27 段:16 段来自豆包、10 段来自 Tencent + Fish、1 段来自 Fish。这与原稿所述“26 段,18 + 8”不一致;后者不能继续当作当前工程结果。
Forced Alignment 定位给定文本,不能恢复未知文本
当文本已经人工确认,但时间不可靠时,可以尝试强制对齐。它根据给定音频和文本估计声学边界,不负责发现所有漏词,也不能让错误文本自动变正确。若所有转写来源都漏掉某句话,应先回听或重新识别,不能凭空交给对齐器补全。
工程保存的 FA 文件有 26 句,其中 9 句的平均分数低于 0.1。该分数不能跨模型直接比较,也不是已经校准的正确概率;低分提示复核,不能保证其他句子都准确。重叠说话、方言、歌唱和背景音乐仍可能导致错位。
Gemini 角色映射、时间窗口匹配和 FA 都可以提供候选,但最终目标是同一套可复核字幕,而不是把每个模型在不同区间的最佳结果简单拼接后宣布整体最优。
从这个案例得到的选型方法
对这段素材,值得继续试验的是:以较可靠区间为起点,用其他来源定位漏段,单独修复时间与角色,并保留人工审核入口。是否值得四源融合,还要比较新增成本、延迟和复核工作量。
原稿的统一价格表没有保留可复核的计价来源、地区和完整耗时日志,不能用它宣称某组合“成本可忽略”。后续记录应区分上传、服务排队、推理、轮询和下载时间;本地模型另记设备、预热和资源成本。准确率提高多少、每分钟素材减少多少人工修订,比星级总分更能指导生产选型。
下一轮应使用事先固定、覆盖不同角色和噪声条件的样本,发布允许公开的转写基准、版本与配置,分别统计 CER、漏段、边界误差、DER 和人工修订时长。当前案例已经说明:字段齐全不等于结果准确,模型间一致不等于真值,融合结果也需要独立验收。