07 — STT 模块

源码目录:src/vocal10n/stt/

职责

  • 以 16 kHz 单声道采集麦克风音频。
  • 在转写前可选执行 TTS 回放回声消除。
  • 以滑动窗口流式方式运行 FasterWhisper。
  • 发出 partial(实时)与 confirmed(稳定)文本事件。
  • 过滤幻觉文本与明显重复。
  • 可选进行轻量说话人标记(diarisation)。

文件

文件作用
audio_capture.pysounddevice 输入流、环形缓冲、设备枚举
playback_aec.pyPlaybackTimeline + AdaptiveEchoCanceller(NLMS + DTD)
engine.pySTTEngine(FasterWhisper 封装)
transcript.py片段管理:partial 与 confirmed 切分
filters.py幻觉过滤、邻接去重、短语重复抑制、音素纠错
diarizer.py可选说话人标记
worker.py从环形缓冲拉流并驱动引擎的后台线程
controller.pySTT tab 使用的公开接口

流式策略

采集层每 0.2 秒写入一帧到环形缓冲。工作线程循环:

  1. 读取末尾 window_seconds(默认 6.5)的音频。
  2. 调用 STTEngine.transcribe(),返回 SegmentResult[](text、start、end、avg_logprobno_speech_prob、可用时含词级置信度)。
  3. 每段先过 filters.HallucinationFilter,再做邻接去重与短语重复抑制,避免 Whisper 在噪声下循环输出。
  4. 按规则分段:
    • Pendingend 位于窗口尾部 confirm_threshold 秒内。
    • Confirmed:早于阈值,或年龄超过 max_segment_age(强制刷新,避免长句不切分导致卡住)。
  5. 对 pending 尾部发布 STT_PARTIAL,对新稳定片段发布 STT_CONFIRMED

识别上下文(见 14 — 知识库与 RAG)会拼接进 Whisper initial_prompt,并受 initial_prompt_capacity 限制。

幻觉过滤

filters.py 包含多层防护:

  • 静态过滤表。config/filters.txt 读取常见幻觉短语(如静音时的 “Thank you for watching”)。匹配则丢弃。
  • 邻接去重。 与上一条 confirmed 相同或近似时抑制输出。
  • 短语重复抑制。 检测短片段连续 N 次重复(Whisper 常见失效模式)。
  • 音素索引。 结合 stt_terms/context_gaming.txt 等,对领域词进行模糊纠错。

完整过滤表可在知识库页通过 vocal10n.ui.widgets.filter_list_editor 编辑。

回放感知 AEC

启用 TTS 时,合成语音可能被麦克风再次采集并转写,形成回声环。playback_aec.py 的 AEC 层用于阻断:

flowchart LR
    Mic([mic]) --> AEC["AdaptiveEchoCanceller<br/>(NLMS, length filter_taps)"]
    TTSPlay([TTS playback]) --> Timeline[PlaybackTimeline]
    Timeline -->|reference signal| AEC
    AEC --> DTD{"Double-talk?<br/>mic > dt_threshold × echo"}
    DTD -- yes --> Freeze["Freeze NLMS weights<br/>(still apply filter)"]
    DTD -- no --> Adapt[Adapt NLMS weights]
    Freeze --> Out([clean mic to Whisper])
    Adapt --> Out
  • PlaybackTimeline 是线程安全的回放音频环形缓冲,在 AudioPlayer 调用 sd.play() 时打时间戳。
  • AdaptiveEchoCanceller 每个 mic chunk 执行:
    1. PlaybackTimeline 取参考信号,并通过互相关估计声学延迟(上限 aec.max_delay_ms)。
    2. 执行长度为 aec.filter_taps 的块式 NLMS,自适应步长为 aec.step_size
    3. 运行双讲检测:若 mic 能量超过估计回声能量的 aec.dt_threshold 倍,则冻结权重更新,但仍应用当前滤波器,避免说话重叠时模型漂移。

该方案在提交 f334773 中引入。

说话人标记

diarizer.py 提供轻量级分段说话人标记:当 SystemState.speaker_tagging 开启时,为 confirmed 段加 [S1][S2] 等前缀。该实现面向流式实时场景,不是离线高精度分析模型。