mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-30 15:23:56 +08:00
Merge branch 'manager-web-logo-i18n' of https://github.com/xinnan-tech/xiaozhi-esp32-server into new
This commit is contained in:
@@ -69,6 +69,7 @@ class ConnectionHandler:
|
||||
self.server = server # 保存server实例的引用
|
||||
|
||||
self.need_bind = False # 是否需要绑定设备
|
||||
self.bind_completed_event = asyncio.Event()
|
||||
self.bind_code = None # 绑定设备的验证码
|
||||
self.last_bind_prompt_time = 0 # 上次播放绑定提示的时间戳(秒)
|
||||
self.bind_prompt_interval = 60 # 绑定提示播放间隔(秒)
|
||||
@@ -268,30 +269,43 @@ class ConnectionHandler:
|
||||
f"保存记忆后关闭连接失败: {close_error}"
|
||||
)
|
||||
|
||||
async def _discard_message_with_bind_prompt(self):
|
||||
"""丢弃消息并检查是否需要播放绑定提示"""
|
||||
current_time = time.time()
|
||||
# 检查是否需要播放绑定提示
|
||||
if current_time - self.last_bind_prompt_time >= self.bind_prompt_interval:
|
||||
self.last_bind_prompt_time = current_time
|
||||
# 复用现有的绑定提示逻辑
|
||||
from core.handle.receiveAudioHandle import check_bind_device
|
||||
|
||||
asyncio.create_task(check_bind_device(self))
|
||||
|
||||
async def _route_message(self, message):
|
||||
"""消息路由"""
|
||||
# 检查是否已经获取到真实的绑定状态
|
||||
if not self.bind_completed_event.is_set():
|
||||
# 还没有获取到真实状态,等待直到获取到真实状态或超时
|
||||
try:
|
||||
await asyncio.wait_for(self.bind_completed_event.wait(), timeout=1)
|
||||
except asyncio.TimeoutError:
|
||||
# 超时仍未获取到真实状态,丢弃消息
|
||||
await self._discard_message_with_bind_prompt()
|
||||
return
|
||||
|
||||
# 已经获取到真实状态,检查是否需要绑定
|
||||
if self.need_bind:
|
||||
# 需要绑定,丢弃消息
|
||||
await self._discard_message_with_bind_prompt()
|
||||
return
|
||||
|
||||
# 不需要绑定,继续处理消息
|
||||
|
||||
if isinstance(message, str):
|
||||
await handleTextMessage(self, message)
|
||||
elif isinstance(message, bytes):
|
||||
if self.vad is None or self.asr is None:
|
||||
return
|
||||
|
||||
# 未绑定设备直接丢弃所有音频,不进行ASR处理
|
||||
if self.need_bind:
|
||||
current_time = time.time()
|
||||
# 检查是否需要播放绑定提示
|
||||
if (
|
||||
current_time - self.last_bind_prompt_time
|
||||
>= self.bind_prompt_interval
|
||||
):
|
||||
self.last_bind_prompt_time = current_time
|
||||
# 复用现有的绑定提示逻辑
|
||||
from core.handle.receiveAudioHandle import check_bind_device
|
||||
|
||||
asyncio.create_task(check_bind_device(self))
|
||||
# 直接丢弃音频,不进行ASR处理
|
||||
return
|
||||
|
||||
# 处理来自MQTT网关的音频包
|
||||
if self.conn_from_mqtt_gateway and len(message) >= 16:
|
||||
handled = await self._process_mqtt_audio_message(message)
|
||||
@@ -415,6 +429,15 @@ class ConnectionHandler:
|
||||
|
||||
def _initialize_components(self):
|
||||
try:
|
||||
if self.tts is None:
|
||||
self.tts = self._initialize_tts()
|
||||
# 打开语音合成通道
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.tts.open_audio_channels(self), self.loop
|
||||
)
|
||||
if self.need_bind:
|
||||
self.bind_completed_event.set()
|
||||
return
|
||||
self.selected_module_str = build_module_string(
|
||||
self.config.get("selected_module", {})
|
||||
)
|
||||
@@ -438,17 +461,10 @@ class ConnectionHandler:
|
||||
|
||||
# 初始化声纹识别
|
||||
self._initialize_voiceprint()
|
||||
|
||||
# 打开语音识别通道
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.asr.open_audio_channels(self), self.loop
|
||||
)
|
||||
if self.tts is None:
|
||||
self.tts = self._initialize_tts()
|
||||
# 打开语音合成通道
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.tts.open_audio_channels(self), self.loop
|
||||
)
|
||||
|
||||
"""加载记忆"""
|
||||
self._initialize_memory()
|
||||
@@ -463,6 +479,7 @@ class ConnectionHandler:
|
||||
self.logger.bind(tag=TAG).error(f"实例化组件失败: {e}")
|
||||
|
||||
def _init_prompt_enhancement(self):
|
||||
|
||||
# 更新上下文信息
|
||||
self.prompt_manager.update_context_info(self, self.client_ip)
|
||||
enhanced_prompt = self.prompt_manager.build_enhanced_prompt(
|
||||
@@ -498,7 +515,11 @@ class ConnectionHandler:
|
||||
|
||||
def _initialize_asr(self):
|
||||
"""初始化ASR"""
|
||||
if self._asr.interface_type == InterfaceType.LOCAL:
|
||||
if (
|
||||
self._asr is not None
|
||||
and hasattr(self._asr, "interface_type")
|
||||
and self._asr.interface_type == InterfaceType.LOCAL
|
||||
):
|
||||
# 如果公共ASR是本地服务,则直接返回
|
||||
# 因为本地一个实例ASR,可以被多个连接共享
|
||||
asr = self._asr
|
||||
@@ -538,6 +559,8 @@ class ConnectionHandler:
|
||||
async def _initialize_private_config_async(self):
|
||||
"""从接口异步获取差异化配置(异步版本,不阻塞主循环)"""
|
||||
if not self.read_config_from_api:
|
||||
self.need_bind = False
|
||||
self.bind_completed_event.set()
|
||||
return
|
||||
try:
|
||||
begin_time = time.time()
|
||||
@@ -550,6 +573,8 @@ class ConnectionHandler:
|
||||
self.logger.bind(tag=TAG).info(
|
||||
f"{time.time() - begin_time} 秒,异步获取差异化配置成功: {json.dumps(filter_sensitive_info(private_config), ensure_ascii=False)}"
|
||||
)
|
||||
self.need_bind = False
|
||||
self.bind_completed_event.set()
|
||||
except DeviceNotFoundException as e:
|
||||
self.need_bind = True
|
||||
private_config = {}
|
||||
@@ -1173,6 +1198,11 @@ class ConnectionHandler:
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
# 重置音频流控器(取消后台任务并清空队列)
|
||||
if hasattr(self, "audio_rate_controller") and self.audio_rate_controller:
|
||||
self.audio_rate_controller.reset()
|
||||
self.logger.bind(tag=TAG).debug("已重置音频流控器")
|
||||
|
||||
self.logger.bind(tag=TAG).debug(
|
||||
f"清理结束: TTS队列大小={self.tts.tts_text_queue.qsize()}, 音频队列大小={self.tts.tts_audio_queue.qsize()}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user