feat: whisper 新增 decode_full 无VAD整段解码参数并改为整条删除式幻觉清洗

解决转写漏句(有人说话但没识别出来)问题:silero VAD 对呻吟/轻语/BGM
混叠声学切段能力天然不足,把真话当非语音剔除(实测 savr-1054 全片仅
召回 115 条)。新增 decode_full 参数(默认 false 保持 VAD 现状):

- decode_full=true 时强制无 VAD 整段解码 + 跳过自动 VAD 分析,救回被
  剔除的弱语音(savr-1054 全片 115 条 → 340 条)
- 副作用是长时寒暄套话幻觉(おやすみなさい/ご視聴ありがとうございま
  した 等),whisper 转录后连带时间戳整条删除(clean_japanese_ha
  lllucinations),不留下 '-' 占位污染下游(占位会渲染进 ASS 成减号)
- llm-translate 翻译后同样整条删除中文长时寒暄幻觉(clean_srt_text)
- 短时(≤15s)相同词可能是剧情真实道晚安,保留(15s 阈值实测校准)
- subtitle_cleanup 由 '-' 占位式改为整条删除式 + 剩余重编号,新增
  JAPANESE_HALLUCINATION_TOKENS 词表

新增工作流 learn-translate(学习资料转译+翻译字幕)示范 decode_full
用法,并确立参数标注约定:params._note_<参数名> 存放设定理由与正反例、
_node_help 放节点参数手册(_ 前缀说明键,节点执行时忽略,零运行影响)。

调研记录见 docs/调研-whisper漏句与decode_full验证.md(A/B 实验、结论
修正与 5 个待决问题)。
This commit is contained in:
2026-09-07 17:21:04 +08:00
parent c063aed1f1
commit a8fe133aa4
10 changed files with 695 additions and 106 deletions
@@ -0,0 +1,138 @@
# 调研记录:whisper "说话没识别" 漏句问题 与 decode_full 方案验证
> 本文档记录 2026-09 对"转写时有人说话但没识别出来(漏句/漏识别)"问题的完整调研过程、
> 实验数据与结论修正。调研中发现**早期结论被后续更严谨的验证推翻**,特此如实记录,
> 供后续对话继续推进时参考,避免重复踩坑。
>
> 状态:**调研暂告段落,方案未定稿,代码改动未提交**。详见文末"当前状态"。
---
## 1. 问题背景
用户反馈:whisper 转写时**动态配置参数**(自动 VAD 调参),生成的字幕中有时出现
"有人说话但没识别出来"的情况,怀疑与动态参数配置有关。
链路(demo/learn-translate):提音(ffmpeg-extract) → 转写(faster-whisper) → 翻译(llm) → ASS。
whisper 节点关键动态逻辑(改动前):
- `vad_filter=true`(默认开启)
- `WOV_AUTO_VAD=1`(默认):每视频信号分析 → 动态生成 `vad_parameters`
`nodes/vad_profiler.py`,按静音比例/BGM 覆盖/长停顿 四分支给 threshold/min_silence/speech_pad
- `chunk_seconds=60` 分块、`condition_on_previous_text=false``beam_size=1`
---
## 2. 实验一:savr-1054 全片 A/BVAD vs 无VAD
素材:`/mnt/fnOS/123/savr-1054/4k2.me@savr01054_2_8k.mp4`1383s,呻吟/BGM 密集)。
| 配置 | 全片条数 | 覆盖时长 | 幻觉长段 |
| --- | --- | --- | --- |
| 生产 VADvad_filter=true+自动VADthreshold0.5/ms1000/pad200 | 115 | 621s | 0 |
| 无 VADdecode_full 前身) | 369 | 983s | 有(119-149s、600-630s 30s"ご視聴…" |
- 无 VAD 确实**大幅增加召回**115→369),其中 65-135s 的"入ってるところ見える?
/奥までジュボジュボ入ってるよ"等与线上 CN.srt 空洞吻合 → **当时判定为"救回真话"**
- 但无 VAD 副作用明显:119-149s/600-630s 出现 30s 长"ご視聴ありがとうございました"幻觉。
### 2.1 人声分离(demucs)实验
- `htdemucs --two-stems=vocals` 分离后:**vocals 轨 VAD 切段与混音几乎一样**(瓶颈是
silero 对呻吟/轻语本身概率低,不是底噪);
- 分离 vocals + 无VAD 与混音无VAD 召回相当(16 vs 15 条/窗口)→ **人声分离不解决问题**
只是把音乐底噪去掉,呻吟/轻语仍是低概率语音。
### 2.2 min_silence / threshold 扫描
- 固定 threshold=0.5 只调 min_silence(300→2000ms):真话召回**不变**450s 窗口恒 1 条、
546s 窗口恒 1 条)→ **只调 min_silence 无效**(它只决定断句,不能把 silero 没标成
语音的弱语音变成语音段);
- 调 threshold(0.3~0.6):覆盖仅 44%→45%,真话也救不回(呻吟/BGM 混叠使 silero 切段能力
天然不足)。
### 2.3 每片独立 VAD / 精细能量分段 模拟
- "每 60s 块独立调参"24 块中 11 块会落到 bgm 分支(thr0.3),但段切更碎、覆盖不升,
**NO_VAD 降级反而新增 60s/36s/20s 空洞 + 幻觉**sim_perchunk 318 条,1080-1140s 整段空);
- 精细能量分段(RMS>900 切语音候选段):连真实说话段都定位错(1065-1115s 只找到 3 小段、
解码出幻觉)→ **能量/VAD 前置切段对混叠声学都不可靠**
---
## 3. 关键结论修正(重要)
### 3.1 "能量低=幻觉" 是错的
savr-1174 上精确验证:**938s 轻语真话 mean -40dBVAD 与无VAD 都能稳定识别**;
而 120s/140s/210s 真话区 mean 仅 -45~-48dB(整片录音电平低),**whisper 仍稳定识别**。
### 3.2 "稳定性(跨配置一致)= 真话" 是相对可靠的判据
- 真话(938s"吸い付かないでよ"、1065s"そういうプレイ好きな人?"):VAD/无VAD/beam1/beam5
**多配置稳定复现同一句**
- 幻听(1260s"手ついてたら…"):VAD 配置下变"おやすみなさい"、无VAD 才出该句 → 内容
跨配置**不稳定** = 无真实语音锚点。
### 3.3 置信度字段无法区分真幻
faster-whisper segment 的 `avg_logprob` / `no_speech_prob`:真话 60s(avg_logprob -0.42) 比
幻觉 1260s(-0.63) 还高;no_speech_prob 幻觉 330s(0.28) 比真话 1065s(0.30) 还低 → **不可用**
### 3.4 "decode_full 救回 VAD 漏掉的真话 2.7 倍" —— 被推翻
savr-1174 全片:decode_full(beam1) 463 条 vs 生产 VAD 170 条,早期结论是"救回弱语音"。
**逐条 + 分层抽样 VAD 复查后**
- decode_full 新增内容中,**大量(抽样 45 条中 20 条 VAD 静默)是 VAD 静默段的幻听**,
beam1 把噪声/重复碎片劣化转写成"词句"(如"何がやばいんだ"实为"何?何?何?"、2243s
beam1/beam5 结果不同=不稳定);
- 真正被救回的低电平真话(120s/140s/210s**VAD 其实也能识别**(只是旧自动 VAD 参数
或分块把它们漏了)→ 说明问题在**旧自动 VAD 参数选取**而非 VAD 机制本身。
### 3.5 无法用单一信号完美区分真幻
| 信号 | 效果 |
| --- | --- |
| 能量/RMS | 无效:savr-1174 录音电平低,真话-45dB vs 幻听-51dB 难分;高响度(如-22dB 效果音段)也可能是幻听 |
| avg_logprob/no_speech | 无效(见 3.3 |
| 寒暄词表 | 有效但覆盖面窄(savr-1174 decode_full 后寒暄类已 0 命中,即已被清干净) |
| **VAD 复查**decode_full 后逐条用 VAD 复查,VAD 能识别才保留) | **相对最可靠**,但会误删 VAD 漏掉的短真语气词(うん/はい/んー),且切窗不准会误删响亮真话 |
---
## 4. 代码改动现状(未提交)
以下改动已写入工作区(`git status` 可见),**未经用户确认提交**
| 文件 | 改动 | 状态 |
| --- | --- | --- |
| `nodes/subtitle_cleanup.py` | 幻觉清洗改为**整条删除式**`remove_hallucination_entries`:≥15s 命中寒暄词表 → 序号+时间轴+文本全删、剩余重编号);新增日语词表 `JAPANESE_HALLUCINATION_TOKENS` | 已改 |
| `nodes/whisper.py` | 新增 `decode_full` 参数(默认 false):true 时无VAD 整段解码 + 跳过自动VAD + 日语幻觉整条删除 | 已改 |
| `nodes/llm.py` | `clean_srt_text` 由替换 `-` 占位改为整条删除;回滚了临时的 `-` 跳过逻辑 | 已改 |
| `workflows/learn-translate.json` | 新工作流"学习资料转译+翻译字幕"decode_full=true;每参数 `_note_<名>` 标注理由+正反例;`_node_help` 参数手册 | 新增 |
| `tests/*` | test_hallucination_mask 重写为删除式;whisper decode_full 测试;learn-translate 加载/标注测试;test_seed 计数 3→4 | 已改 |
| `AGENTS.md` | decode_full 说明、工作流表、参数标注约定 | 已改 |
测试:相关 97 passed(全量 357 passed / 5 个既有环境失败与本次无关:ffmpeg 4.2 不支持
`force_divisible_by` 滤镜、home 目录解析)。
**端到端已验证**savr-1174 前 200s decode_full → 幻觉整条删除(无 0-90s 占位重叠)、
真实内容 60.03s 起时间轴正确、翻译 36 条、ASS 72 Dialogue 0 噪点。
---
## 5. 待决问题(新对话继续)
1. **decode_full 是否值得作为默认增强**savr-1174 显示其对呻吟/BGM 密集视频**弊大于利**
(新增大量幻听),但对纯对话/低电平场景(120s 真话)有效。可能只适合特定声学;
2. **"VAD 复查过滤"方案是否落地**:可保留 decode_full 救回的真话并剔幻听,但需解决
短真语气词误删与切窗不稳问题;实现成本中等;
3. **旧自动 VAD 参数为何漏低电平真话**(120s 这类 VAD 单窗能识别但整片 A 漏了)——
可能是分块边界/自动参数分支误判,值得单独排查;
4. **现有代码改动去留**subtitle_cleanup 整条删除式、whisper decode_full、learn-translate
工作流——保留、调整还是回滚待定;
5. **如何真正"听"音频验证**(本调研最大局限:未实际听音,靠多配置转写交叉推断)。
### 实验产物(临时文件,可复用)
```
/tmp/savr1054_2.wav savr-1054 全片 16k 音频
/tmp/savr1054_2_vocals16k.wav demucs 分离 vocals 轨
/tmp/run_A_vad.srt savr-1054 生产VAD 全片 (115条)
/tmp/run_B_novad.srt savr-1054 无VAD 全片 (369条)
/tmp/savr1174_1.wav savr-1174 全片 16k 音频
/tmp/savr1174_A_vad.srt savr-1174 生产VAD 全片 (170条)
/tmp/savr1174_B_decodefull.srt savr-1174 decode_full beam1 (463条)
/tmp/savr1174_D.srt savr-1174 decode_full beam5 (336条)
```