326 lines
6.9 KiB
Markdown
326 lines
6.9 KiB
Markdown
# 最终问题总结和解决方案
|
||
|
||
## 🎉 进展
|
||
|
||
### 已解决的问题
|
||
1. ✅ 语法错误已修复
|
||
2. ✅ 按钮事件可以触发
|
||
3. ✅ 录音功能可以启动
|
||
4. ✅ 录音文件可以生成
|
||
5. ✅ duration/fileSize undefined 问题已绕过
|
||
|
||
### 当前问题
|
||
|
||
#### 问题1: WebSocket 连接不稳定
|
||
```
|
||
09:19:33.273 🔌 WebSocket 状态:0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED
|
||
09:20:28.752 ⭕ 录音已停止 WebSocket...
|
||
09:20:28.753 等待重新连接 WebSocket 连接...
|
||
09:20:28.907 WebSocket onOpen:[Object] {}
|
||
```
|
||
|
||
**原因**:
|
||
- WebSocket 在录音过程中断开了
|
||
- 触发了自动重连机制
|
||
- 重连后才开始发送数据
|
||
|
||
**影响**:
|
||
- 延迟了数据发送
|
||
- 可能导致超时
|
||
|
||
#### 问题2: 服务器还是 60 秒超时
|
||
```
|
||
09:21:29.115 📥 消息内容:{"type":"error","msg":"idle timeout"}
|
||
```
|
||
|
||
**原因**:
|
||
- 服务器配置可能没有生效
|
||
- 或者服务器没有重启
|
||
|
||
## 🔧 解决方案
|
||
|
||
### 方案1: 确保服务器配置生效(最重要)
|
||
|
||
#### 步骤1: 检查服务器 .env 文件
|
||
|
||
```bash
|
||
# 在服务器上执行
|
||
cat lover/.env
|
||
```
|
||
|
||
应该看到:
|
||
```
|
||
VOICE_CALL_IDLE_TIMEOUT=120
|
||
```
|
||
|
||
#### 步骤2: 确认服务器已重启
|
||
|
||
```bash
|
||
# 停止旧进程
|
||
pkill -f "uvicorn.*main:app"
|
||
|
||
# 确认进程已停止
|
||
ps aux | grep uvicorn
|
||
|
||
# 启动新进程
|
||
cd /path/to/lover
|
||
uvicorn main:app --host 0.0.0.0 --port 30101 --reload
|
||
```
|
||
|
||
#### 步骤3: 验证配置
|
||
|
||
启动后,服务器应该加载新的配置。可以在服务器日志中看到。
|
||
|
||
### 方案2: 修复 WebSocket 连接稳定性
|
||
|
||
#### 问题分析
|
||
|
||
WebSocket 在录音过程中断开,可能的原因:
|
||
1. 网络不稳定
|
||
2. 服务器主动断开(因为超时)
|
||
3. 客户端没有发送心跳
|
||
|
||
#### 解决方案A: 添加心跳机制
|
||
|
||
在 `phone.vue` 中添加心跳:
|
||
|
||
```javascript
|
||
data() {
|
||
return {
|
||
heartbeatTimer: null
|
||
}
|
||
},
|
||
|
||
connectWebSocket() {
|
||
// ... 原有代码 ...
|
||
|
||
this.socketTask.onOpen((res) => {
|
||
console.log('WebSocket onOpen:', res)
|
||
this.startTimer()
|
||
|
||
// 启动心跳
|
||
this.startHeartbeat()
|
||
})
|
||
},
|
||
|
||
startHeartbeat() {
|
||
// 清除旧的心跳
|
||
if (this.heartbeatTimer) {
|
||
clearInterval(this.heartbeatTimer)
|
||
}
|
||
|
||
// 每 30 秒发送一次心跳
|
||
this.heartbeatTimer = setInterval(() => {
|
||
if (this.socketTask && this.socketTask.readyState === 1) {
|
||
console.log('💓 发送心跳')
|
||
this.socketTask.send({
|
||
data: 'ping',
|
||
success: () => {
|
||
console.log('✅ 心跳发送成功')
|
||
},
|
||
fail: (err) => {
|
||
console.error('❌ 心跳发送失败:', err)
|
||
}
|
||
})
|
||
}
|
||
}, 30000) // 30 秒
|
||
},
|
||
|
||
stopCall() {
|
||
// ... 原有代码 ...
|
||
|
||
// 停止心跳
|
||
if (this.heartbeatTimer) {
|
||
clearInterval(this.heartbeatTimer)
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 解决方案B: 增加 WebSocket 连接检查
|
||
|
||
在发送数据前,确保 WebSocket 已连接:
|
||
|
||
```javascript
|
||
async sendAudioInChunks(audioData) {
|
||
// 检查 WebSocket 状态
|
||
if (!this.socketTask || this.socketTask.readyState !== 1) {
|
||
console.error('❌ WebSocket 未连接,等待重连...')
|
||
|
||
// 等待最多 5 秒
|
||
for (let i = 0; i < 50; i++) {
|
||
await new Promise(resolve => setTimeout(resolve, 100))
|
||
if (this.socketTask && this.socketTask.readyState === 1) {
|
||
console.log('✅ WebSocket 已重连')
|
||
break
|
||
}
|
||
}
|
||
|
||
// 如果还是未连接,放弃
|
||
if (!this.socketTask || this.socketTask.readyState !== 1) {
|
||
uni.showToast({
|
||
title: 'WebSocket 连接失败',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
}
|
||
|
||
// 继续原有逻辑...
|
||
}
|
||
```
|
||
|
||
### 方案3: 临时增加客户端等待时间
|
||
|
||
如果服务器配置无法立即修改,可以临时在客户端增加等待:
|
||
|
||
```javascript
|
||
// 在 sendAudioInChunks 中
|
||
const chunkDelay = 200 // 从 100ms 增加到 200ms
|
||
```
|
||
|
||
这样可以延长发送时间,减少超时的可能性。
|
||
|
||
## 📊 当前状态分析
|
||
|
||
### 时间线
|
||
|
||
```
|
||
09:19:28 - 开始录音
|
||
09:19:33 - 停止录音(录音 5 秒)
|
||
09:19:33 - WebSocket 状态检查
|
||
09:20:28 - WebSocket 断开并重连(约 55 秒后)
|
||
09:20:28 - WebSocket 重新连接
|
||
09:21:29 - 收到 idle timeout(61 秒后)
|
||
```
|
||
|
||
### 问题分析
|
||
|
||
1. **录音到停止**:正常(5 秒)
|
||
2. **WebSocket 断开**:在 55 秒时断开,说明服务器还是 60 秒超时
|
||
3. **重连后发送**:重连成功,但已经超过 60 秒
|
||
4. **收到超时**:服务器返回 idle timeout
|
||
|
||
### 结论
|
||
|
||
**服务器配置没有生效!** 服务器还在使用 60 秒的超时配置。
|
||
|
||
## 🚀 立即操作
|
||
|
||
### 1. 确认服务器配置
|
||
|
||
在服务器上执行:
|
||
```bash
|
||
cat lover/.env | grep VOICE_CALL_IDLE_TIMEOUT
|
||
```
|
||
|
||
应该显示:
|
||
```
|
||
VOICE_CALL_IDLE_TIMEOUT=120
|
||
```
|
||
|
||
### 2. 重启服务器
|
||
|
||
```bash
|
||
pkill -f "uvicorn.*main:app"
|
||
cd /path/to/lover
|
||
uvicorn main:app --host 0.0.0.0 --port 30101 --reload
|
||
```
|
||
|
||
### 3. 验证服务器启动
|
||
|
||
服务器启动后,应该看到:
|
||
```
|
||
INFO: Uvicorn running on http://0.0.0.0:30101
|
||
```
|
||
|
||
### 4. 重新测试
|
||
|
||
1. 进入语音通话页面
|
||
2. 按住说话 3-5 秒
|
||
3. 松开按钮
|
||
4. 观察日志
|
||
|
||
### 5. 预期结果
|
||
|
||
如果服务器配置生效,应该:
|
||
- ✅ 不会在 60 秒时断开
|
||
- ✅ 能够完整发送音频数据
|
||
- ✅ 收到 ASR 识别结果
|
||
- ✅ 收到 LLM 回复
|
||
- ✅ 听到 TTS 语音
|
||
|
||
## 🐛 如果还是超时
|
||
|
||
### 检查1: 服务器是否真的重启了
|
||
|
||
```bash
|
||
ps aux | grep uvicorn
|
||
```
|
||
|
||
查看进程的启动时间,应该是最近的时间。
|
||
|
||
### 检查2: 配置文件是否正确
|
||
|
||
```bash
|
||
cat lover/.env
|
||
```
|
||
|
||
确认 `VOICE_CALL_IDLE_TIMEOUT=120` 存在。
|
||
|
||
### 检查3: 服务器是否加载了配置
|
||
|
||
在服务器代码中添加日志:
|
||
|
||
```python
|
||
# lover/config.py
|
||
print(f"VOICE_CALL_IDLE_TIMEOUT = {settings.VOICE_CALL_IDLE_TIMEOUT}")
|
||
```
|
||
|
||
重启服务器后应该看到:
|
||
```
|
||
VOICE_CALL_IDLE_TIMEOUT = 120
|
||
```
|
||
|
||
## 💡 临时解决方案
|
||
|
||
如果服务器配置无法立即生效,可以:
|
||
|
||
### 方案A: 直接修改服务器代码
|
||
|
||
在 `lover/routers/voice_call.py` 中:
|
||
|
||
```python
|
||
async def _idle_watchdog(self):
|
||
timeout = 120 # 直接硬编码 120 秒
|
||
# timeout = settings.VOICE_CALL_IDLE_TIMEOUT or 0
|
||
if timeout <= 0:
|
||
return
|
||
# ...
|
||
```
|
||
|
||
### 方案B: 加快客户端发送速度
|
||
|
||
在 `phone.vue` 中:
|
||
|
||
```javascript
|
||
const chunkSize = 3200
|
||
const chunkDelay = 50 // 从 100ms 减少到 50ms
|
||
```
|
||
|
||
这样可以更快地发送完数据。
|
||
|
||
## 📞 需要帮助?
|
||
|
||
如果以上方案都不行,请提供:
|
||
1. 服务器 `.env` 文件内容
|
||
2. 服务器启动日志
|
||
3. 服务器是否真的重启了
|
||
4. 客户端完整日志
|
||
|
||
---
|
||
|
||
**当前状态**: 代码正常,但服务器配置未生效
|
||
**核心问题**: 服务器还在使用 60 秒超时
|
||
**解决方案**: 确认服务器配置并重启
|
||
**预计时间**: 5 分钟
|