whisper-transcribe/references/empty-segment-gap.md

60 lines
2.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Empty Segment Gap空白段漏转写
## 症状
全长转写结果中,某一段(几秒到几十秒)输出为**空文本**
```json
{"start": 1376.42, "end": 1406.42, "text": ""}
```
该段音频实际包含清晰的对话,单独提取转写完全正常。
## 根因
与 [token repetition loop](token-repetition-loop.md) 同一类问题——**Whisper autoregressive decoder 的边界故障**,但表现不同:
- 循环幻觉:低置信度边界 → 猜错第一个 token → 自激放大 → 重复输出
- 空段:低置信度边界 → decoder 全程置信度不足 → 输出空字符串
两种故障都发生在长音频中后段20+ 分钟),此时 KV cache 积累了大量上下文,在模糊发音、犹豫、或者声学域偏移(如不同录音源的拼接点)处模型失去对齐。
## 修复方案
与 token repetition loop 相同——**检测 → 提取 → 冷启动重转写**
### 检测
```python
def find_empty_gaps(segments: list[dict], min_duration: float = 1.0) -> list[int]:
"""返回所有空文本且时长超过 min_duration 的 segment 索引"""
return [
i for i, s in enumerate(segments)
if not s.get("text", "").strip() and s["end"] - s["start"] > min_duration
]
```
### 合并连续空段
连续的空段合并为一个时间范围,避免对同一片音频发起多次重转写。
### 冷启动重写
ffmpeg 切出该段 → `mlx_whisper.transcribe()` 不带前序上下文 → 如果重转写得到有效文本,替换回原结果。
**如果重转写也无输出**(说明该段确实是静音/纯噪),则直接删除该段,不保留原始空字幕。这与旧版"保留 originals"的做法不同——避免静音段冷启动逼出幻听。
## 为什么 VAD 过滤没抓到
VAD静音过滤检查的是 segments 是否落在 ffmpeg `silencedetect` 标记的**静音区**。空段大多不是静音(有音乐、背景音甚至人声),只是 Whisper 的 decoder 没有输出文字——所以不会被 VAD 丢弃。
## 在脚本中的实现
空段检测已合并进 `fix_repetition_loops()` 函数Mode B与循环检测共享重转写逻辑骨架。位于 `whisper_transcribe.py` 的 Post-processing 阶段,在 `--no-clean` 未设置时运行。
核心行为:
- 空段 ≥2s → 标记为异常,冷启动重试
- 重试成功 → 用新 segments 替换
- 重试仍为空 → `del` 删除该段(不入库)
- 使用 `reversed(ranges)` 逆序遍历,防止多区间替换时的索引漂移