6.9 KiB
6.9 KiB
最终问题总结和解决方案
🎉 进展
已解决的问题
- ✅ 语法错误已修复
- ✅ 按钮事件可以触发
- ✅ 录音功能可以启动
- ✅ 录音文件可以生成
- ✅ 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 文件
# 在服务器上执行
cat lover/.env
应该看到:
VOICE_CALL_IDLE_TIMEOUT=120
步骤2: 确认服务器已重启
# 停止旧进程
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 在录音过程中断开,可能的原因:
- 网络不稳定
- 服务器主动断开(因为超时)
- 客户端没有发送心跳
解决方案A: 添加心跳机制
在 phone.vue 中添加心跳:
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 已连接:
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: 临时增加客户端等待时间
如果服务器配置无法立即修改,可以临时在客户端增加等待:
// 在 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 秒后)
问题分析
- 录音到停止:正常(5 秒)
- WebSocket 断开:在 55 秒时断开,说明服务器还是 60 秒超时
- 重连后发送:重连成功,但已经超过 60 秒
- 收到超时:服务器返回 idle timeout
结论
服务器配置没有生效! 服务器还在使用 60 秒的超时配置。
🚀 立即操作
1. 确认服务器配置
在服务器上执行:
cat lover/.env | grep VOICE_CALL_IDLE_TIMEOUT
应该显示:
VOICE_CALL_IDLE_TIMEOUT=120
2. 重启服务器
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. 重新测试
- 进入语音通话页面
- 按住说话 3-5 秒
- 松开按钮
- 观察日志
5. 预期结果
如果服务器配置生效,应该:
- ✅ 不会在 60 秒时断开
- ✅ 能够完整发送音频数据
- ✅ 收到 ASR 识别结果
- ✅ 收到 LLM 回复
- ✅ 听到 TTS 语音
🐛 如果还是超时
检查1: 服务器是否真的重启了
ps aux | grep uvicorn
查看进程的启动时间,应该是最近的时间。
检查2: 配置文件是否正确
cat lover/.env
确认 VOICE_CALL_IDLE_TIMEOUT=120 存在。
检查3: 服务器是否加载了配置
在服务器代码中添加日志:
# 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 中:
async def _idle_watchdog(self):
timeout = 120 # 直接硬编码 120 秒
# timeout = settings.VOICE_CALL_IDLE_TIMEOUT or 0
if timeout <= 0:
return
# ...
方案B: 加快客户端发送速度
在 phone.vue 中:
const chunkSize = 3200
const chunkDelay = 50 // 从 100ms 减少到 50ms
这样可以更快地发送完数据。
📞 需要帮助?
如果以上方案都不行,请提供:
- 服务器
.env文件内容 - 服务器启动日志
- 服务器是否真的重启了
- 客户端完整日志
当前状态: 代码正常,但服务器配置未生效
核心问题: 服务器还在使用 60 秒超时
解决方案: 确认服务器配置并重启
预计时间: 5 分钟