Ai_GirlFriend/xuniYou/优化总结.md

254 lines
6.3 KiB
Markdown
Raw Permalink Normal View History

2026-02-28 18:04:34 +08:00
# 语音通话 "idle timeout" 问题 - 优化总结
## 📅 日期
2026-02-28
## 🎯 问题描述
用户在使用语音通话功能时,录音后总是收到 "idle timeout" 错误无法完成完整的对话流程ASR → LLM → TTS
## 🔍 问题根因
### 1. 客户端发送参数不符合官方推荐
- **问题**: 每片 8KB间隔 50ms发送速度是实际音频速度的 5 倍
- **影响**: 虽然在官方范围内1KB-16KB但不是最优参数
### 2. 服务器超时时间不足
- **问题**: 默认 60 秒超时,但 ASR + LLM + TTS 可能需要更长时间
- **影响**: 在处理完成前就超时断开
### 3. 测试音频太短
- **问题**: 之前测试只有 9KB约 0.3 秒)
- **影响**: ASR 无法识别太短的音频
## ✅ 已实施的优化
### 优化1: 调整客户端分片参数(符合官方推荐)
**文件**: `xuniYou/pages/chat/phone.vue`
**修改内容**:
```javascript
// 优化前
const chunkSize = 8192 // 8KB
const chunkDelay = 50 // 50ms
// 优化后
const chunkSize = 3200 // 3.2KB(官方推荐)
const chunkDelay = 100 // 100ms官方推荐
```
**理由**:
- PCM 16kHz 单声道: 32000 bytes/秒
- 100ms 音频 = 32000 × 0.1 = 3200 bytes
- 完美匹配实时音频流速度
### 优化2: 增加服务器超时时间
**文件**: `lover/.env`
**修改内容**:
```bash
# 新增配置
VOICE_CALL_IDLE_TIMEOUT=120
```
**理由**:
- 从 60 秒增加到 120 秒
- 给 ASR + LLM + TTS 留出足够处理时间
- 避免在处理过程中超时
## 📊 优化效果对比
### 发送速度对比
| 参数 | 优化前 | 优化后 |
|------|--------|--------|
| 每片大小 | 8192 bytes | 3200 bytes |
| 发送间隔 | 50ms | 100ms |
| 发送速率 | 163840 bytes/s | 32000 bytes/s |
| 音频速率 | 32000 bytes/s | 32000 bytes/s |
| 速率比 | 5.12 倍 | 1 倍 ✅ |
### 时间线对比
**优化前**:
```
0s - 用户说话 1 秒
1s - 一次性发送 32KB
1s - ASR 无法处理
60s - 超时断开 ❌
```
**优化后**:
```
0s - 用户说话 5 秒
5s - 开始分片发送3200 bytes/片100ms 间隔)
10s - 发送完成ASR 识别
11s - LLM 生成回复
13s - TTS 合成语音
15s - 客户端播放音频 ✅
```
## 🔧 需要执行的操作
### ⚠️ 重要:必须重启服务器
修改 `.env` 文件后,必须重启 FastAPI 服务器才能生效:
```bash
# 1. 停止旧进程
pkill -f "uvicorn.*main:app"
# 2. 启动新进程
cd /path/to/lover
uvicorn main:app --host 0.0.0.0 --port 30101 --reload
```
### 客户端重新编译
在 HBuilderX 中重新运行项目到手机或模拟器。
## 📱 测试指南
### 测试步骤
1. 打开 App进入语音通话页面
2. 按住"按住说话"按钮
3. **清晰地说 3-5 秒的话**(重要!)
4. 松开按钮
5. 等待响应(应该在 20 秒内完成)
### 预期结果
- ✅ 看到"发送中..."提示
- ✅ 看到"识别中..."提示
- ✅ 收到文字回复
- ✅ 听到语音回复
- ✅ 没有 "idle timeout" 错误
### 关键日志
**客户端应该看到**:
```
📦 开始分片发送(官方推荐参数)
📊 总大小: 160000 bytes
📊 每片大小: 3200 bytes
📊 发送间隔: 100 ms
✅ 所有音频片段发送完成,共 50 片
✅ 结束标记发送成功
📋 收到控制消息, type: reply_text
🎵 收到音频数据流
📋 收到控制消息, type: reply_end
```
**服务器应该看到**:
```
ASR connection opened
ASR event end=True sentence=[识别的文字]
Handle sentence: [识别的文字]
```
## 📚 相关文档
已创建的文档:
1. `最新优化说明.md` - 详细的优化说明
2. `测试检查清单.md` - 测试步骤和检查项
3. `语音通话完整流程图.md` - 可视化流程图
4. `官方文档分析和正确实现.md` - 技术分析
5. `问题定位总结.md` - 问题诊断过程
## 🎓 技术要点总结
### 1. Paraformer-realtime-v2 的正确用法
- 必须流式发送音频数据
- 每包 1KB-16KB建议 3200 bytes
- 发送间隔建议 100ms
- 发送完成后必须发送 "end" 标记
### 2. PCM 音频参数
- 采样率: 16000 Hz
- 位深度: 16 bit (2 bytes)
- 声道数: 1单声道
- 数据速率: 32000 bytes/秒
### 3. 超时设置
- 空闲超时: 120 秒(从 60 秒增加)
- 静默超时: 60 秒(无语音活动)
- 给 ASR + LLM + TTS 留出足够时间
### 4. 录音要求
- 最少 2-3 秒
- 建议 3-5 秒
- 清晰发音,避免噪音
## 🐛 故障排查
### 如果还是出现 "idle timeout"
1. **检查服务器是否重启**
```bash
ps aux | grep uvicorn
```
2. **检查配置是否生效**
```bash
cat lover/.env | grep VOICE_CALL_IDLE_TIMEOUT
```
3. **检查录音时长**
- 客户端日志中的 "总大小" 应该 > 96000 bytes3 秒)
4. **检查服务器日志**
```bash
tail -f lover/logs/app.log
```
### 常见问题
**Q: 为什么要用 3200 bytes**
A: 因为 PCM 16kHz 单声道每秒 32000 bytes100ms 就是 3200 bytes这是官方推荐的参数。
**Q: 为什么要延迟 100ms**
A: 模拟实时音频流的速度,让 ASR 能够边收边识别,而不是一次性收到大块数据。
**Q: 为什么要发送 "end" 标记?**
A: 告诉服务器音频发送完毕,触发 ASR 的最终识别,否则 ASR 会一直等待更多数据。
**Q: 为什么要说 3-5 秒?**
A: 太短的音频(< 1 ASR 可能无法识别3-5 秒是比较合适的长度
## 🎉 预期成果
优化完成后,语音通话应该能够:
1. ✅ 用户说话 3-5 秒
2. ✅ 客户端分片发送3200 bytes/片100ms 间隔)
3. ✅ 服务器 ASR 识别成功
4. ✅ LLM 生成回复
5. ✅ TTS 合成语音
6. ✅ 客户端播放音频
7. ✅ 整个流程在 20-30 秒内完成
8. ✅ 不再出现 "idle timeout" 错误
## 💡 下一步建议
如果基本功能正常,可以考虑:
1. **实时流式录音**: 使用 `onFrameRecorded` 实现真正的实时传输
2. **降低延迟**: 优化 LLM 和 TTS 的响应速度
3. **打断功能**: 允许用户在 AI 说话时打断
4. **多轮对话**: 优化对话历史管理
5. **情感识别**: 根据用户语气调整回复风格
## 📞 需要帮助?
如果测试失败,请提供:
1. 客户端完整日志
2. 服务器日志
3. 录音信息(大小、时长)
4. 错误信息
---
**优化完成时间**: 2026-02-28
**优化人员**: Kiro AI Assistant
**状态**: ✅ 已完成,待测试