mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 10:03:54 +08:00
update:server连接api (#747)
* update:server连接manager-api * update:读取智能体模型配置 * update:添加默认模型的按钮 * update:优化配置读取方式 * update:server兼容manager接口改造 * update:优化私有配置加载 * update:加载私有模型配置
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import copy
|
||||
import json
|
||||
import uuid
|
||||
import time
|
||||
@@ -17,16 +18,16 @@ from core.utils.util import (
|
||||
get_string_no_punctuation_or_emoji,
|
||||
extract_json_from_string,
|
||||
get_ip_info,
|
||||
initialize_modules,
|
||||
)
|
||||
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
||||
from core.handle.sendAudioHandle import sendAudioMessage
|
||||
from core.handle.receiveAudioHandle import handleAudioMessage
|
||||
from core.handle.functionHandler import FunctionHandler
|
||||
from plugins_func.register import Action, ActionResponse
|
||||
from config.private_config import PrivateConfig
|
||||
from core.auth import AuthMiddleware, AuthenticationError
|
||||
from core.utils.auth_code_gen import AuthCodeGenerator
|
||||
from core.mcp.manager import MCPManager
|
||||
from config.config_loader import get_private_config_from_api
|
||||
|
||||
TAG = __name__
|
||||
|
||||
@@ -41,7 +42,7 @@ class ConnectionHandler:
|
||||
def __init__(
|
||||
self, config: Dict[str, Any], _vad, _asr, _llm, _tts, _memory, _intent
|
||||
):
|
||||
self.config = config
|
||||
self.config = copy.deepcopy(config)
|
||||
self.logger = setup_logging()
|
||||
self.auth = AuthMiddleware(config)
|
||||
|
||||
@@ -95,15 +96,12 @@ class ConnectionHandler:
|
||||
self.iot_descriptors = {}
|
||||
self.func_handler = None
|
||||
|
||||
self.cmd_exit = self.config["CMD_exit"]
|
||||
self.cmd_exit = self.config["exit_commands"]
|
||||
self.max_cmd_length = 0
|
||||
for cmd in self.cmd_exit:
|
||||
if len(cmd) > self.max_cmd_length:
|
||||
self.max_cmd_length = len(cmd)
|
||||
|
||||
self.private_config = None
|
||||
self.auth_code_gen = AuthCodeGenerator.get_instance()
|
||||
self.is_device_verified = False # 添加设备验证状态标志
|
||||
self.close_after_chat = False # 是否在聊天结束后关闭连接
|
||||
self.use_function_call_mode = False
|
||||
if self.config["selected_module"]["Intent"] == "function_call":
|
||||
@@ -121,7 +119,6 @@ class ConnectionHandler:
|
||||
|
||||
# 进行认证
|
||||
await self.auth.authenticate(self.headers)
|
||||
device_id = self.headers.get("device-id", None)
|
||||
|
||||
# 认证通过,继续处理
|
||||
self.websocket = ws
|
||||
@@ -130,39 +127,6 @@ class ConnectionHandler:
|
||||
self.welcome_msg = self.config["xiaozhi"]
|
||||
self.welcome_msg["session_id"] = self.session_id
|
||||
await self.websocket.send(json.dumps(self.welcome_msg))
|
||||
# Load private configuration if device_id is provided
|
||||
bUsePrivateConfig = self.config.get("use_private_config", False)
|
||||
if bUsePrivateConfig and device_id:
|
||||
try:
|
||||
self.private_config = PrivateConfig(
|
||||
device_id, self.config, self.auth_code_gen
|
||||
)
|
||||
await self.private_config.load_or_create()
|
||||
# 判断是否已经绑定
|
||||
owner = self.private_config.get_owner()
|
||||
self.is_device_verified = owner is not None
|
||||
|
||||
if self.is_device_verified:
|
||||
await self.private_config.update_last_chat_time()
|
||||
|
||||
llm, tts = self.private_config.create_private_instances()
|
||||
if all([llm, tts]):
|
||||
self.llm = llm
|
||||
self.tts = tts
|
||||
self.logger.bind(tag=TAG).info(
|
||||
f"Loaded private config and instances for device {device_id}"
|
||||
)
|
||||
else:
|
||||
self.logger.bind(tag=TAG).error(
|
||||
f"Failed to create instances for device {device_id}"
|
||||
)
|
||||
self.private_config = None
|
||||
except Exception as e:
|
||||
self.logger.bind(tag=TAG).error(
|
||||
f"Error initializing private config: {e}"
|
||||
)
|
||||
self.private_config = None
|
||||
raise
|
||||
|
||||
# 异步初始化
|
||||
self.executor.submit(self._initialize_components)
|
||||
@@ -211,10 +175,11 @@ class ConnectionHandler:
|
||||
await handleAudioMessage(self, message)
|
||||
|
||||
def _initialize_components(self):
|
||||
"""初始化组件"""
|
||||
self._initialize_models()
|
||||
|
||||
"""加载提示词"""
|
||||
self.prompt = self.config["prompt"]
|
||||
if self.private_config:
|
||||
self.prompt = self.private_config.private_config.get("prompt", self.prompt)
|
||||
self.dialogue.put(Message(role="system", content=self.prompt))
|
||||
|
||||
"""加载记忆"""
|
||||
@@ -222,13 +187,100 @@ class ConnectionHandler:
|
||||
"""加载意图识别"""
|
||||
self._initialize_intent()
|
||||
"""加载位置信息"""
|
||||
self.client_ip_info = get_ip_info(self.client_ip)
|
||||
self.client_ip_info = get_ip_info(self.client_ip, self.logger)
|
||||
if self.client_ip_info is not None and "city" in self.client_ip_info:
|
||||
self.logger.bind(tag=TAG).info(f"Client ip info: {self.client_ip_info}")
|
||||
self.prompt = self.prompt + f"\nuser location:{self.client_ip_info}"
|
||||
|
||||
self.dialogue.update_system_message(self.prompt)
|
||||
|
||||
def _initialize_models(self):
|
||||
read_config_from_api = self.config.get("read_config_from_api", False)
|
||||
"""如果是从配置文件获取,则进行二次实例化"""
|
||||
if not read_config_from_api:
|
||||
return
|
||||
"""从接口获取差异化的配置进行二次实例化,非全量重新实例化"""
|
||||
try:
|
||||
private_config = get_private_config_from_api(
|
||||
self.config,
|
||||
self.headers.get("device-id", None),
|
||||
self.headers.get("client-id", None),
|
||||
)
|
||||
private_config["delete_audio"] = self.config["delete_audio"]
|
||||
self.logger.bind(tag=TAG).info(f"获取差异化配置成功: {private_config}")
|
||||
except Exception as e:
|
||||
self.logger.bind(tag=TAG).error(f"获取差异化配置失败: {e}")
|
||||
private_config = {}
|
||||
|
||||
init_vad, init_asr, init_llm, init_tts, init_memory, init_intent = (
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
)
|
||||
if private_config.get("VAD", None) is not None:
|
||||
init_vad = True
|
||||
self.config["vad"] = private_config["VAD"]
|
||||
self.config["selected_module"]["VAD"] = private_config["selected_module"][
|
||||
"VAD"
|
||||
]
|
||||
if private_config.get("ASR", None) is not None:
|
||||
init_asr = True
|
||||
self.config["asr"] = private_config["ASR"]
|
||||
self.config["selected_module"]["ASR"] = private_config["selected_module"][
|
||||
"ASR"
|
||||
]
|
||||
if private_config.get("LLM", None) is not None:
|
||||
init_llm = True
|
||||
self.config["llm"] = private_config["LLM"]
|
||||
self.config["selected_module"]["LLM"] = private_config["selected_module"][
|
||||
"LLM"
|
||||
]
|
||||
if private_config.get("TTS", None) is not None:
|
||||
init_tts = True
|
||||
self.config["tts"] = private_config["TTS"]
|
||||
self.config["selected_module"]["TTS"] = private_config["selected_module"][
|
||||
"TTS"
|
||||
]
|
||||
if private_config.get("Memory", None) is not None:
|
||||
init_memory = True
|
||||
self.config["memory"] = private_config["Memory"]
|
||||
self.config["selected_module"]["Memory"] = private_config[
|
||||
"selected_module"
|
||||
]["Memory"]
|
||||
if private_config.get("Intent", None) is not None:
|
||||
init_intent = True
|
||||
self.config["intent"] = private_config["Intent"]
|
||||
self.config["selected_module"]["Intent"] = private_config[
|
||||
"selected_module"
|
||||
]["Intent"]
|
||||
if private_config.get("prompt", None) is not None:
|
||||
self.config["prompt"] = private_config["prompt"]
|
||||
try:
|
||||
modules = initialize_modules(
|
||||
self.logger,
|
||||
private_config,
|
||||
init_vad,
|
||||
init_asr,
|
||||
init_llm,
|
||||
init_tts,
|
||||
init_memory,
|
||||
init_intent,
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.bind(tag=TAG).error(f"初始化组件失败: {e}")
|
||||
modules = {}
|
||||
if modules.get("tts", None) is not None:
|
||||
self.tts = modules["tts"]
|
||||
if modules.get("llm", None) is not None:
|
||||
self.llm = modules["llm"]
|
||||
if modules.get("intent", None) is not None:
|
||||
self.intent = modules["intent"]
|
||||
if modules.get("memory", None) is not None:
|
||||
self.memory = modules["memory"]
|
||||
|
||||
def _initialize_memory(self):
|
||||
"""初始化记忆模块"""
|
||||
device_id = self.headers.get("device-id", None)
|
||||
@@ -281,34 +333,7 @@ class ConnectionHandler:
|
||||
if m.role == "system":
|
||||
m.content = prompt
|
||||
|
||||
async def _check_and_broadcast_auth_code(self):
|
||||
"""检查设备绑定状态并广播认证码"""
|
||||
if not self.private_config.get_owner():
|
||||
auth_code = self.private_config.get_auth_code()
|
||||
if auth_code:
|
||||
# 发送验证码语音提示
|
||||
text = f"请在后台输入验证码:{' '.join(auth_code)}"
|
||||
self.recode_first_last_text(text)
|
||||
future = self.executor.submit(self.speak_and_play, text)
|
||||
self.tts_queue.put(future)
|
||||
return False
|
||||
return True
|
||||
|
||||
def isNeedAuth(self):
|
||||
bUsePrivateConfig = self.config.get("use_private_config", False)
|
||||
if not bUsePrivateConfig:
|
||||
# 如果不使用私有配置,就不需要验证
|
||||
return False
|
||||
return not self.is_device_verified
|
||||
|
||||
def chat(self, query):
|
||||
if self.isNeedAuth():
|
||||
self.llm_finish_task = True
|
||||
future = asyncio.run_coroutine_threadsafe(
|
||||
self._check_and_broadcast_auth_code(), self.loop
|
||||
)
|
||||
future.result()
|
||||
return True
|
||||
|
||||
self.dialogue.put(Message(role="user", content=query))
|
||||
|
||||
@@ -391,13 +416,6 @@ class ConnectionHandler:
|
||||
def chat_with_function_calling(self, query, tool_call=False):
|
||||
self.logger.bind(tag=TAG).debug(f"Chat with function calling start: {query}")
|
||||
"""Chat with function calling for intent detection using streaming"""
|
||||
if self.isNeedAuth():
|
||||
self.llm_finish_task = True
|
||||
future = asyncio.run_coroutine_threadsafe(
|
||||
self._check_and_broadcast_auth_code(), self.loop
|
||||
)
|
||||
future.result()
|
||||
return True
|
||||
|
||||
if not tool_call:
|
||||
self.dialogue.put(Message(role="user", content=query))
|
||||
|
||||
Reference in New Issue
Block a user