mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-30 05:13:59 +08:00
refactor: 重构底层代码,抽离conn,调整消息处理器并创建传输层接口。
feature: 支持mqtt非桥接版本。
This commit is contained in:
@@ -13,15 +13,80 @@ import concurrent.futures
|
||||
from abc import ABC, abstractmethod
|
||||
from config.logger import setup_logging
|
||||
from typing import Optional, Tuple, List
|
||||
from core.handle.receiveAudioHandle import startToChat
|
||||
from core.handle.reportHandle import enqueue_asr_report
|
||||
# from core.handle.receiveAudioHandle import startToChat # 旧的handler
|
||||
# from core.handle.reportHandle import enqueue_asr_report # 旧的handler
|
||||
# from core.handle.receiveAudioHandle import handleAudioMessage # 旧的handler
|
||||
# 使用新的processor替代
|
||||
from core.utils.util import remove_punctuation_and_length
|
||||
from core.handle.receiveAudioHandle import handleAudioMessage
|
||||
|
||||
TAG = __name__
|
||||
logger = setup_logging()
|
||||
|
||||
|
||||
async def handleAudioMessage(conn, message):
|
||||
"""兼容函数:使用新的processor处理音频消息"""
|
||||
try:
|
||||
# 获取transport接口
|
||||
transport = getattr(conn, 'transport', None)
|
||||
if not transport:
|
||||
logger.error("SessionContext中没有transport接口")
|
||||
return
|
||||
|
||||
# 使用AudioReceiveProcessor处理音频消息
|
||||
from core.processors.audio_receive_processor import AudioReceiveProcessor
|
||||
processor = AudioReceiveProcessor()
|
||||
|
||||
# 处理音频消息
|
||||
await processor.handle_audio_message(conn, transport, message)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理音频消息失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
async def startToChat(conn, text):
|
||||
"""兼容函数:使用新的processor开始聊天"""
|
||||
try:
|
||||
# 获取transport接口
|
||||
transport = getattr(conn, 'transport', None)
|
||||
if not transport:
|
||||
logger.error("SessionContext中没有transport接口")
|
||||
return
|
||||
|
||||
# 使用ChatProcessor处理聊天
|
||||
from core.processors.chat_processor import ChatProcessor
|
||||
processor = ChatProcessor()
|
||||
|
||||
# 开始聊天
|
||||
await processor.handle_chat(conn, transport, text)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"开始聊天失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def enqueue_asr_report(conn, text, audio_data):
|
||||
"""兼容函数:使用新的processor处理ASR报告"""
|
||||
try:
|
||||
# 获取transport接口
|
||||
transport = getattr(conn, 'transport', None)
|
||||
if not transport:
|
||||
logger.error("SessionContext中没有transport接口")
|
||||
return
|
||||
|
||||
# 使用ReportProcessor处理报告
|
||||
from core.processors.report_processor import ReportProcessor
|
||||
processor = ReportProcessor()
|
||||
|
||||
# 处理ASR报告
|
||||
processor.enqueue_asr_report(conn, text, audio_data)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"ASR报告处理失败: {e}")
|
||||
|
||||
|
||||
class ASRProviderBase(ABC):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -127,7 +127,16 @@ class DeviceIoTExecutor(ToolExecutor):
|
||||
send_message = json.dumps(
|
||||
{"type": "iot", "commands": [command]}
|
||||
)
|
||||
await self.conn.websocket.send(send_message)
|
||||
|
||||
# 使用transport接口发送消息
|
||||
if hasattr(self.conn, 'transport') and self.conn.transport:
|
||||
await self.conn.transport.send(send_message)
|
||||
elif hasattr(self.conn, 'websocket') and self.conn.websocket:
|
||||
# 兼容旧版本
|
||||
logger.warning("未找到SessionContext的传输层接口, 回退使用旧版conn.websocket发送消息")
|
||||
await self.conn.websocket.send(send_message)
|
||||
else:
|
||||
raise AttributeError("无法找到可用的传输层接口")
|
||||
return
|
||||
|
||||
raise Exception(f"未找到设备{device_name}的方法{method_name}")
|
||||
|
||||
@@ -96,7 +96,7 @@ class MCPClient:
|
||||
self.call_results.pop(id)
|
||||
|
||||
|
||||
async def send_mcp_message(conn, payload: dict):
|
||||
async def send_mcp_message(conn, payload: dict, transport=None):
|
||||
"""Helper to send MCP messages, encapsulating common logic."""
|
||||
if not conn.features.get("mcp"):
|
||||
logger.bind(tag=TAG).warning("客户端不支持MCP,无法发送MCP消息")
|
||||
@@ -105,13 +105,23 @@ async def send_mcp_message(conn, payload: dict):
|
||||
message = json.dumps({"type": "mcp", "payload": payload})
|
||||
|
||||
try:
|
||||
await conn.websocket.send(message)
|
||||
# 优先使用传入的transport,否则尝试从conn获取
|
||||
if transport:
|
||||
await transport.send(message)
|
||||
elif hasattr(conn, 'websocket'):
|
||||
# 兼容旧版本
|
||||
await conn.websocket.send(message)
|
||||
elif hasattr(conn, 'transport'):
|
||||
# 新架构
|
||||
await conn.transport.send(message)
|
||||
else:
|
||||
raise AttributeError("无法找到可用的传输层接口")
|
||||
logger.bind(tag=TAG).info(f"成功发送MCP消息: {message}")
|
||||
except Exception as e:
|
||||
logger.bind(tag=TAG).error(f"发送MCP消息失败: {e}")
|
||||
|
||||
|
||||
async def handle_mcp_message(conn, mcp_client: MCPClient, payload: dict):
|
||||
async def handle_mcp_message(conn, mcp_client: MCPClient, payload: dict, transport=None):
|
||||
"""处理MCP消息,包括初始化、工具列表和工具调用响应等"""
|
||||
logger.bind(tag=TAG).info(f"处理MCP消息: {str(payload)[:100]}")
|
||||
|
||||
@@ -196,7 +206,7 @@ async def handle_mcp_message(conn, mcp_client: MCPClient, payload: dict):
|
||||
next_cursor = result.get("nextCursor", "")
|
||||
if next_cursor:
|
||||
logger.bind(tag=TAG).info(f"有更多工具,nextCursor: {next_cursor}")
|
||||
await send_mcp_tools_list_continue_request(conn, next_cursor)
|
||||
await send_mcp_tools_list_continue_request(conn, next_cursor, transport)
|
||||
else:
|
||||
await mcp_client.set_ready(True)
|
||||
logger.bind(tag=TAG).info("所有工具已获取,MCP客户端准备就绪")
|
||||
@@ -224,7 +234,7 @@ async def handle_mcp_message(conn, mcp_client: MCPClient, payload: dict):
|
||||
)
|
||||
|
||||
|
||||
async def send_mcp_initialize_message(conn):
|
||||
async def send_mcp_initialize_message(conn, transport=None):
|
||||
"""发送MCP初始化消息"""
|
||||
|
||||
vision_url = get_vision_url(conn.config)
|
||||
@@ -256,10 +266,10 @@ async def send_mcp_initialize_message(conn):
|
||||
},
|
||||
}
|
||||
logger.bind(tag=TAG).info("发送MCP初始化消息")
|
||||
await send_mcp_message(conn, payload)
|
||||
await send_mcp_message(conn, payload, transport)
|
||||
|
||||
|
||||
async def send_mcp_tools_list_request(conn):
|
||||
async def send_mcp_tools_list_request(conn, transport=None):
|
||||
"""发送MCP工具列表请求"""
|
||||
payload = {
|
||||
"jsonrpc": "2.0",
|
||||
@@ -267,10 +277,10 @@ async def send_mcp_tools_list_request(conn):
|
||||
"method": "tools/list",
|
||||
}
|
||||
logger.bind(tag=TAG).debug("发送MCP工具列表请求")
|
||||
await send_mcp_message(conn, payload)
|
||||
await send_mcp_message(conn, payload, transport)
|
||||
|
||||
|
||||
async def send_mcp_tools_list_continue_request(conn, cursor: str):
|
||||
async def send_mcp_tools_list_continue_request(conn, cursor: str, transport=None):
|
||||
"""发送带有cursor的MCP工具列表请求"""
|
||||
payload = {
|
||||
"jsonrpc": "2.0",
|
||||
@@ -279,7 +289,7 @@ async def send_mcp_tools_list_continue_request(conn, cursor: str):
|
||||
"params": {"cursor": cursor},
|
||||
}
|
||||
logger.bind(tag=TAG).info(f"发送带cursor的MCP工具列表请求: {cursor}")
|
||||
await send_mcp_message(conn, payload)
|
||||
await send_mcp_message(conn, payload, transport)
|
||||
|
||||
|
||||
async def call_mcp_tool(
|
||||
|
||||
@@ -14,8 +14,6 @@ from abc import ABC, abstractmethod
|
||||
from config.logger import setup_logging
|
||||
from core.utils.tts import MarkdownCleaner
|
||||
from core.utils.output_counter import add_device_output
|
||||
from core.handle.reportHandle import enqueue_tts_report
|
||||
from core.handle.sendAudioHandle import sendAudioMessage
|
||||
from core.utils.util import audio_bytes_to_data_stream, audio_to_data_stream
|
||||
from core.providers.tts.dto.dto import (
|
||||
TTSMessageDTO,
|
||||
@@ -28,6 +26,72 @@ TAG = __name__
|
||||
logger = setup_logging()
|
||||
|
||||
|
||||
async def sendAudioMessage(conn, sentenceType, audios, text):
|
||||
"""兼容函数:使用新的processor发送音频消息"""
|
||||
try:
|
||||
# 获取transport接口
|
||||
transport = getattr(conn, 'transport', None)
|
||||
if not transport:
|
||||
logger.error("SessionContext中没有transport接口")
|
||||
return
|
||||
|
||||
# 使用AudioSendProcessor发送音频
|
||||
from core.processors.audio_send_processor import AudioSendProcessor
|
||||
processor = AudioSendProcessor()
|
||||
|
||||
# 处理TTS开始消息
|
||||
if conn.tts.tts_audio_first_sentence:
|
||||
logger.info(f"发送第一段语音: {text}")
|
||||
conn.tts.tts_audio_first_sentence = False
|
||||
await processor.send_tts_message(conn, transport, "start", None)
|
||||
|
||||
if sentenceType == SentenceType.FIRST:
|
||||
await processor.send_tts_message(conn, transport, "sentence_start", text)
|
||||
|
||||
await processor.send_audio(conn, transport, audios)
|
||||
|
||||
# 发送句子开始消息
|
||||
if sentenceType is not SentenceType.MIDDLE:
|
||||
logger.info(f"发送音频消息: {sentenceType}, {text}")
|
||||
|
||||
# 发送结束消息(如果是最后一个文本)
|
||||
if conn.llm_finish_task and sentenceType == SentenceType.LAST:
|
||||
await processor.send_tts_message(conn, transport, "stop", None)
|
||||
conn.client_is_speaking = False
|
||||
if conn.close_after_chat:
|
||||
if hasattr(transport, 'close'):
|
||||
await transport.close()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"发送音频消息失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def enqueue_tts_report(conn, audio_data, text):
|
||||
"""兼容函数:使用新的processor处理TTS报告"""
|
||||
try:
|
||||
# 获取transport接口
|
||||
transport = getattr(conn, 'transport', None)
|
||||
if not transport:
|
||||
logger.error("SessionContext中没有transport接口")
|
||||
return
|
||||
|
||||
# 使用ReportProcessor处理报告
|
||||
from core.processors.report_processor import ReportProcessor
|
||||
processor = ReportProcessor()
|
||||
|
||||
# 异步执行报告
|
||||
if hasattr(conn, 'loop') and conn.loop:
|
||||
# 直接调用同步方法
|
||||
processor.enqueue_tts_report(conn, text, audio_data)
|
||||
else:
|
||||
logger.warning("SessionContext中没有事件循环,跳过TTS报告")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"TTS报告处理失败: {e}")
|
||||
|
||||
|
||||
class TTSProviderBase(ABC):
|
||||
def __init__(self, config, delete_audio_file):
|
||||
self.interface_type = InterfaceType.NON_STREAM
|
||||
|
||||
Reference in New Issue
Block a user