# wechat_voice_asr_sop

适用场景：GA 微信前端收到 `voice_item`（`.silk`）后，自动转写并把文本注入 prompt。

## 已验证实现落点
- 文件：`frontends/wechatapp.py`
- 媒体下载：`_MEDIA_KEYS` 把 `voice_item` 映射为 `.silk`
- 转换与识别：
  - `_silk_to_wav(path)`: 用 `pilk.SilkDecoder(pcm_rate=24000)` 把 silk 解到 PCM，再封装成 24kHz/16-bit/单声道 WAV
  - `_transcribe_audio_file(path)`: `.silk` 先转 WAV，再用 `sherpa_onnx.OfflineRecognizer.from_sense_voice(...)` 做离线识别
- 注入点：`on_message()` 会把转写结果追加成 `[用户语音转写: ...]`，再传给 `agent.put_task(prompt, source="wechat")`

## 依赖与模型
- Python 依赖：`pilk`, `sherpa-onnx`, `numpy`
- 模型：SenseVoice 目录需包含
  - `model.int8.onnx`
  - `tokens.txt`
- 当前实现会在这些根目录下找模型：
  - `_TEMP_DIR`
  - `Path.cwd()`
  - `Path.home()`
- 目录名兼容：
  - `sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17`
  - `sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17-int8`

## 关键参数
- `SilkDecoder(pcm_rate=24000)`
- SenseVoice 初始化：
  - `language='zh'`
  - `use_itn=True`
  - `num_threads=4`

## 典型坑
- 微信语音不是 WAV，必须先把 `.silk` 转成 PCM/WAV，再喂给 ASR。
- `pilk` 这里走的是文件路径式解码，不是内存流接口。
- 模型缺失时 `_get_asr_recognizer()` 会返回：
  - `ASR模型缺失，请放置到 temp/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/`
- 依赖缺失时会返回：
  - `ASR依赖缺失，请安装 sherpa-onnx 和 numpy`

## 最小验证
- 导入 `frontends.wechatapp` 成功
- `pilk.SilkDecoder` / `sherpa_onnx` / `numpy` 可用
- `_find_sensevoice_model_dir()` 命中本地 SenseVoice 模型目录
- `_get_asr_recognizer()` 返回 `ok`

## 排查顺序
1. 先看 `.silk` 是否被 `_dl_media()` 正常下载出来
2. 再看 `_get_asr_recognizer()` 返回的是 `ok` 还是缺依赖/缺模型
3. 再单测 `_transcribe_audio_file(path)` 是否能产出文本
4. 最后确认 `on_message()` 是否把 `[用户语音转写: ...]` 拼进最终 prompt