update:server连接api (#747)

* update:server连接manager-api

* update:读取智能体模型配置

* update:添加默认模型的按钮

* update:优化配置读取方式

* update:server兼容manager接口改造

* update:优化私有配置加载

* update:加载私有模型配置
This commit is contained in:
hrz
2025-04-12 17:36:04 +08:00
committed by GitHub
parent c39ad97b8e
commit 5d69ba0796
57 changed files with 1618 additions and 1066 deletions
+96 -78
View File
@@ -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))