|
|
@@ -36,6 +36,7 @@ class StreamingSession:
|
|
|
|
|
|
# 文本收集(用于日志)
|
|
|
self.llm_text_chunks = [] # 收集LLM流式文本
|
|
|
+ self.asr_text = '' # 最后一次ASR识别结果
|
|
|
|
|
|
# 对话轮次控制
|
|
|
self.response_ended = False # 标记当前轮次是否已结束(避免重复发送结束消息)
|
|
|
@@ -162,7 +163,12 @@ class StreamingSession:
|
|
|
if self.audio_sent_bytes > 0:
|
|
|
# 计算本轮对话的延迟
|
|
|
response_latency = int((time.time() - self.start_time) * 1000) if self.start_time > 0 else 0
|
|
|
- logger.info(f"🔊 [AI回复完成] 音频大小: {self.audio_sent_bytes} bytes ({self.audio_sent_bytes/1024:.1f}KB), 延迟: {response_latency}ms")
|
|
|
+
|
|
|
+ # 打印完整的LLM回复文本
|
|
|
+ full_llm_text = ''.join(self.llm_text_chunks)
|
|
|
+ logger.info(f"🔊 [AI回复完成] 音频: {self.audio_sent_bytes / 1024:.1f}KB, 延迟: {response_latency}ms")
|
|
|
+ if full_llm_text:
|
|
|
+ logger.info(f"💬 [完整回复] {full_llm_text}")
|
|
|
|
|
|
await self.send_control_message({
|
|
|
'type': 'ai_response_end',
|
|
|
@@ -208,6 +214,15 @@ class StreamingSession:
|
|
|
self.audio_sent_bytes = 0
|
|
|
# 不break,继续外层循环等待下一次录音
|
|
|
continue
|
|
|
+ elif isinstance(audio_data, tuple):
|
|
|
+ # 处理文本数据
|
|
|
+ if audio_data[0] == 'llm_text':
|
|
|
+ # LLM文本片段
|
|
|
+ self.llm_text_chunks.append(audio_data[1])
|
|
|
+ elif audio_data[0] == 'asr_text':
|
|
|
+ # ASR识别文本(保存最新的)
|
|
|
+ self.asr_text = audio_data[1]
|
|
|
+ continue
|
|
|
elif audio_data:
|
|
|
# bytes表示音频数据
|
|
|
# 发送AI响应开始消息(仅第一次)
|
|
|
@@ -235,6 +250,10 @@ class StreamingSession:
|
|
|
self.audio_sent_bytes += len(audio_data)
|
|
|
performance_monitor.record_audio_sent(len(audio_data))
|
|
|
logger.debug(f"收到豆包音频: {len(audio_data)} bytes, 总计: {self.audio_sent_bytes} bytes")
|
|
|
+
|
|
|
+ # 监控输出是否过长(超过100KB警告)
|
|
|
+ if self.audio_sent_bytes > 100 * 1024:
|
|
|
+ logger.warning(f"⚠️ AI回复过长: {self.audio_sent_bytes / 1024:.1f}KB,可能需要优化prompt")
|
|
|
else:
|
|
|
# None表示其他事件(文本、状态等),继续等待
|
|
|
logger.debug("收到豆包事件,继续等待音频")
|
|
|
@@ -372,6 +391,7 @@ class StreamingSession:
|
|
|
self.audio_received_bytes = 0
|
|
|
self.audio_sent_bytes = 0
|
|
|
self.llm_text_chunks = [] # 重置文本收集
|
|
|
+ self.asr_text = '' # 重置ASR文本
|
|
|
self.response_ended = False # 重置结束标志
|
|
|
|
|
|
logger.info(f"🎙️ [开始录音] 新一轮对话")
|
|
|
@@ -400,17 +420,24 @@ class StreamingSession:
|
|
|
duration = int((time.time() - self.start_time) * 1000) if self.start_time > 0 else 0
|
|
|
|
|
|
# 记录录音完成信息
|
|
|
- logger.info(f"🎤 [录音完成] 时长: {duration}ms, 音频大小: {self.audio_received_bytes} bytes ({self.audio_received_bytes/1024:.1f}KB)")
|
|
|
+ logger.info(f"🎤 [录音完成] 时长: {duration}ms, 音频: {self.audio_received_bytes / 1024:.1f}KB")
|
|
|
+
|
|
|
+ # 等待一下让ASR完成识别
|
|
|
+ await asyncio.sleep(0.3)
|
|
|
+
|
|
|
+ # 打印ASR识别的完整文本
|
|
|
+ if self.asr_text:
|
|
|
+ logger.info(f"📝 [用户说] {self.asr_text}")
|
|
|
|
|
|
# 等待队列中的音频数据全部发送完成
|
|
|
await asyncio.sleep(0.15)
|
|
|
|
|
|
- # 发送较短的静音帧让豆包VAD检测到结束
|
|
|
- # 豆包配置了 end_smooth_window_ms: 600,需要600ms静音
|
|
|
- # 发送700ms静音确保触发(16kHz 16bit = 32000 bytes/s)
|
|
|
+ # 发送静音帧让豆包VAD检测到结束
|
|
|
+ # 豆包配置了 end_smooth_window_ms: 1200,需要1.2秒静音
|
|
|
+ # 发送1300ms静音确保触发(16kHz 16bit = 32000 bytes/s)
|
|
|
if self.doubao_client:
|
|
|
try:
|
|
|
- silence_duration_ms = 700
|
|
|
+ silence_duration_ms = 1300
|
|
|
silence_bytes = int(16000 * 2 * silence_duration_ms / 1000)
|
|
|
silence_data = b'\x00' * silence_bytes
|
|
|
|