# Day 22 - GLM API 修复 + SenseVoice 语言修复 **日期**: 2025-12-26 **主题**: AI 对话链路修复 --- ## 🔧 GLM API 升级 (10:00) **问题**:Day 21 的 GLM API 调用失败 (Error 400/1210) **原因**:使用了错误的 SDK 和模型名称 **修复**:升级到官方 `zai-sdk` + `glm-4.5-flash` ### 修改对比 | 项目 | 修改前 | 修改后 | |------|--------|--------| | SDK | `openai` | `zai-sdk` | | 模型 | `glm-4-flash` | `glm-4.5-flash` | | 客户端 | `OpenAI(...)` | `ZhipuAiClient(...)` | ### 代码变更 (`glm_client.py`) ```python # 修改前 from openai import OpenAI MODEL = "glm-4-flash" _client = OpenAI(api_key=API_KEY, base_url=API_BASE) # 修改后 from zai import ZhipuAiClient MODEL = "glm-4.5-flash" _client = ZhipuAiClient(api_key=API_KEY) ``` --- ## 🔧 SenseVoice 语言修复 (10:08) **问题**:Day 21 识别出韩语字符 (`그`) **原因**:`language="auto"` 自动检测错误 **修复**:固定为 `language="zh"` 中文 ### 代码变更 (`sensevoice_asr.py`) ```python # 修改前 language="auto" # 修改后 language="zh" # 固定为中文,避免 auto 误判 ``` --- ## 🔧 扬声器杂声修复 (10:48) **问题**:无 TTS 播放时扬声器有杂声 **原因**:`loopback debug` 开关将麦克风信号回环到 I2S 输出 **修复**:在 `audio_player.cpp` 中禁用 loopback 开关 ### 代码变更 (`audio_player.cpp`) ```cpp // 在 setup_mixer() 中 if (switch_name.find("loopback") != std::string::npos) { snd_mixer_selem_set_playback_switch_all(elem, 0); // 禁用 LOG_INFO("DISABLED playback switch for '%s' (noise reduction)", name); } ``` ### 注意事项 - **不能禁用 MIC playback switch**:Day 12 发现禁用会导致麦克风无数据(硬件限制) - 如果此修复不彻底,可能需要硬件层面改进(加磁环、屏蔽线) --- ## 📁 修改文件汇总 | 文件 | 修改内容 | |------|----------| | `glm_client.py` | 升级到 zai-sdk + glm-4.5-flash | | `sensevoice_asr.py` | 语言设置从 auto 改为 zh | | `test_glm.py` | **新增** GLM API 测试脚本 | --- ## 🧪 验证说明 ### 服务器测试步骤 ```bash cd ~/ProgramFiles/OpenAIglasses_for_Navigation # 1. 同步代码(从本地推送或 git pull) # 2. 启动服务器(主程序已集成修复) python app_main.py ``` ### 验证点 - [ ] 语音识别结果为中文(不再出现韩语字符) - [ ] AI 回答与问题相关 (GLM-4.6v-flash) - [ ] VAD 响应灵敏,无首字丢失 - [ ] 导航语音播报正常 (Chipmunk effect 确认为正常现象) --- ## 🔧 VAD 语音截断修复 (14:30) **问题**:语音指令首字经常丢失(如"开始导航"识别为"导航") **原因**:VAD 触发后才开始录制,错过了触发前的几百毫秒关键音节 **修复**:在 `server_vad.py` 中引入 `pre_speech_buffer` 环形缓冲区 (300ms) **效果**:检测到语音时,自动回溯并拼接前 300ms 音频,首字识别率显著提升 ### 代码原理 ```python # 环形缓冲队列 self.pre_speech_buffer = collections.deque(maxlen=PRE_SPEECH_CHUNKS) # 触发时拼接 packet = b''.join(list(self.pre_speech_buffer)) + chunk ``` --- ## 🔧 TTS 语速与音频底噪 (15:50) ### 1. 导航语音语速过快 ("Chipmunk Effect") **现象**:导航提示音(如"远处发现斑马线")语速极快,音调偏高 **调查**: - 检查采样率:确认 Client/Server 均为 16kHz,配置无误 - 检查源文件:发现 `远处发现斑马线.WAV` 实际时长仅 **1.02s**,而 `map.zh-CN.json` 预期 **1.6s** **结论**:源文件录制语速本身较快 **决策**:用户确认偏好此语速,**取消修复**(保持原样) ### 2. 音频回环底噪 **现象**:扬声器有持续静电底噪 **分析**: - 此前怀疑硬件接地问题(手触开发板底噪消失)。 - **最终确认**:连接电脑 USB/串口导致的**共地干扰** (PC 机箱未接地,或 USB 供电干扰)。 **解决方案**: - **移除串口,使用电池独立供电** -> **杂音完全消失**。 - 软件上仍保持 `ADC Playback Volume` 80% 以防万一,但核心问题已由电源隔离解决。 --- ## 🛑 踩坑与反思 (Lessons Learned) 今天开发过程中经历了几个关键的“弯路”,值得记录以避免重蹈覆辙: ### 1. 音频问题的归因偏误 - **弯路**:听到 TTS 语速快 ("Chipmunk Effect"),第一反应是**代码逻辑错误**(认为采样率 8k/16k 不匹配),花费大量时间排查 `audio_compressor` 和 `audio_player`。 - **真相**:实际上是**源文件本身**录制语速就这么快(1.0s vs 预期 1.6s)。 - **教训**:遇到音频异常,**优先检查源文件 (Source Asset)** 的属性,不要预设是代码 BUG。 ### 2. 硬件 Mixer 的隐形耦合 - **弯路**:为了消除回环噪音,直接在代码中将 `ADC Playback Volume` 设为 0(静音)。 - **后果**:导致麦克风采集数据全为 0,一度以为驱动损坏。 - **真相**:该开发板 (V821) 的 Codec 硬件通路上,**ADC Playback Volume 同时控制采集增益**。 - **教训**:嵌入式音频开发中,Mixer 控件往往存在硬件级耦合,调整前需小步验证,不能想当然地“全关”。 ### 3. VAD 的时序陷阱 - **弯路**:语音首字识别丢失,一直在调整 VAD 的**灵敏度阈值 (threshold)**。 - **真相**:阈值再低也需要时间触发,触发时说话人已经发出了第一个音节。 - **教训**:实时语音交互中,**环形缓冲区 (Lookback Buffer)** 是必须的,它能“挽回”触发前的那几百毫秒关键信息。 --- ## 📝 Day 22 总结 | 类别 | 状态 | 说明 | |------|------|------| | GLM API 升级 | ✅ | zai-sdk + glm-4.6v-flash | | SenseVoice 语言修复 | ✅ | language="zh" | | VAD 截断修复 | ✅ | Ring Buffer (300ms) | | TTS 语速排查 | ✅ | 确认源文件特性,用户决定保留 | | 音频底噪优化 | ⚠️ | 软件80%音量,硬件需接地 | | 待服务器验证 | ⏳ | 需要部署并测试 |