edit | blame | history | raw

2026-06-14 X-ASR 尾字掉字排查

用户目标

用户反馈当前 X-ASR 版本偶尔会掉最后一两个字,例如实际说“技术总监让我问你一下”,识别成“技术总监让我问你”或类似结果,要求判断原因和解决方案。

已完成排查

  • 读取全局与项目规则。
  • 检查当前日志与源码:
  • /Users/ar/Library/Application Support/PrivateVoice Input/app.log
  • privatevoice.src/app.go
  • privatevoice.src/internal/audio/recorder.go
  • privatevoice.src/internal/engine/engine_darwin.go
  • 当前运行版本为 2.1.30 (20260613.2201)
  • 当前模型为 x-asr-zh-en-960ms backend=x_asr_streaming

关键证据

  • 日志中存在用户提到的近似失败样本:
  • 2026-06-14 19:54:47 Recognized: 技术总监让我问你一
  • 该结果在 Recognized: 日志阶段已经缺少最后尾字,说明不是粘贴链路、剪贴板或上屏阶段丢字,而是 ASR 最终文本阶段已经掉尾。
  • 当前 X-ASR 已经在 Finish() 中追加 1.5s 静音 padding:
  • xasrTailPaddingSamples = 24000
  • AcceptWaveform(..., xasrTailPadding) 后再 InputFinished()
  • 失败样本录音时长约 2609ms,实际采样 37600,约 2.35s,说明松键停止和音频缓冲之间仍可能遗漏最后约 100-300ms 的真实声音。

判断

问题更像是“松开热键后立刻停止录音导致最后尾音没被采进 buffer”,而不是单纯的 X-ASR flush 不充分。

已有的静音 padding 只能帮助模型处理已经捕获的音频;如果最后一个字的真实声音在松键瞬间还没有进入 pcmBuf,后续补静音无法恢复。

建议修复

低风险方案:只针对 X-ASR 增加松键后的短尾采集保护。

  • 新增一个 engine 能力接口,例如 ReleaseTailCaptureDelay() time.Duration
  • 只有 xasrStreamingEngine 返回 250-350ms,建议先用 300ms
  • stopRecordingLocked(false) 中,在真正 StopAndGetSamples() 前,如果当前引擎声明需要 tail capture,则保持 recorder 继续采集这段时间。
  • SenseVoice、Qwen3-ASR、Moonshine、Parakeet 不实现该接口,延迟为 0,不受影响。
  • 保留现有 X-ASR 1.5s 静音 padding,它仍负责模型 flush。

风险与验证

  • 风险:X-ASR 每次松键后增加约 300ms 识别等待;如果用户立刻开始下一句话,可能多采到一点环境声或下一个字。
  • 回归范围:X-ASR hold-to-talk 为主,不触碰正式上架线模型。
  • 建议验证:
  • 重复测试短句尾音:“技术总监让我问你一下”“你看一下”“确认一下”“可以了”“好了”。
  • 每句至少 20 次,重点观察尾字缺失率。
  • 日志应显示采样数平均增加约 4800 samples(300ms * 16kHz)。
  • 确认 live caption 浮窗仍正常,松键后只增加可接受的短暂处理延迟。