From a6904f6ebd945ee69234a11befd1f5d498652732 Mon Sep 17 00:00:00 2001 From: Sakura-RanChen <1908198662@qq.com> Date: Thu, 9 Apr 2026 17:15:35 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20vad=E7=8B=AC=E7=AB=8B=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E6=88=B3=EF=BC=8C=E7=9B=B8=E5=85=B3=E6=AE=8B=E4=BD=99?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/connection.py | 7 +++---- main/xiaozhi-server/core/handle/receiveAudioHandle.py | 1 + main/xiaozhi-server/core/handle/sendAudioHandle.py | 6 ++++-- main/xiaozhi-server/core/providers/asr/base.py | 6 ++++++ main/xiaozhi-server/core/providers/vad/silero.py | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index b64afd5d..c948b815 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -159,6 +159,7 @@ class ConnectionHandler: self.client_voice_window = deque(maxlen=5) self.first_activity_time = 0.0 # 记录首次活动的时间(毫秒) self.last_activity_time = 0.0 # 统一的活动时间戳(毫秒) + self.vad_last_voice_time = 0.0 # 记录用户最后一次说话的时间(毫秒) self.client_voice_stop = False self.last_is_voice = False @@ -1288,10 +1289,7 @@ class ConnectionHandler: # 标记任务完成 self.report_queue.task_done() - def clearSpeakStatus(self, sentence_id=None): - # 如果sentence_id不匹配,说明是旧轮次的回调,不需要执行 - if sentence_id is not None and sentence_id != self.sentence_id: - return + def clearSpeakStatus(self): self.client_is_speaking = False self.logger.bind(tag=TAG).debug(f"清除服务端讲话状态") @@ -1433,6 +1431,7 @@ class ConnectionHandler: self.client_voice_stop = False self.client_voice_window.clear() self.last_is_voice = False + self.vad_last_voice_time = 0.0 # Clear ASR buffers self.asr_audio.clear() diff --git a/main/xiaozhi-server/core/handle/receiveAudioHandle.py b/main/xiaozhi-server/core/handle/receiveAudioHandle.py index cd53629b..7e234a9e 100644 --- a/main/xiaozhi-server/core/handle/receiveAudioHandle.py +++ b/main/xiaozhi-server/core/handle/receiveAudioHandle.py @@ -77,6 +77,7 @@ async def startToChat(conn: "ConnectionHandler", text): ): await max_out_size(conn) return + # manual 模式下不打断正在播放的内容 if conn.client_is_speaking and conn.client_listen_mode != "manual": await handleAbortMessage(conn) diff --git a/main/xiaozhi-server/core/handle/sendAudioHandle.py b/main/xiaozhi-server/core/handle/sendAudioHandle.py index f62cc582..789d61f6 100644 --- a/main/xiaozhi-server/core/handle/sendAudioHandle.py +++ b/main/xiaozhi-server/core/handle/sendAudioHandle.py @@ -284,8 +284,10 @@ async def send_tts_message(conn: "ConnectionHandler", state, text=None): # 停止音频发送循环(仅在流控器已初始化时调用) if hasattr(conn, "audio_rate_controller") and conn.audio_rate_controller: conn.audio_rate_controller.stop_sending() - # 清除服务端讲话状态,传入 sentence_id 用于判断是否是当前轮次 - conn.clearSpeakStatus(current_sentence_id) + # 检查是否是当前轮次 + if current_sentence_id != conn.sentence_id: + return + conn.clearSpeakStatus() # 发送消息到客户端 await conn.websocket.send(json.dumps(message)) diff --git a/main/xiaozhi-server/core/providers/asr/base.py b/main/xiaozhi-server/core/providers/asr/base.py index 986dd275..6ede6a5d 100644 --- a/main/xiaozhi-server/core/providers/asr/base.py +++ b/main/xiaozhi-server/core/providers/asr/base.py @@ -84,6 +84,12 @@ class ASRProviderBase(ABC): async def handle_voice_stop(self, conn: "ConnectionHandler", asr_audio_task: List[bytes]): """并行处理ASR和声纹识别""" try: + # 如果处于退出流程中,直接关闭连接,不处理新消息 + if conn.close_after_chat or conn.is_exiting: + logger.bind(tag=TAG).info("退出流程中收到新消息,直接关闭连接") + await conn.close() + return + total_start_time = time.monotonic() # 准备音频数据 diff --git a/main/xiaozhi-server/core/providers/vad/silero.py b/main/xiaozhi-server/core/providers/vad/silero.py index 8d3891dc..3682f3b8 100644 --- a/main/xiaozhi-server/core/providers/vad/silero.py +++ b/main/xiaozhi-server/core/providers/vad/silero.py @@ -107,12 +107,12 @@ class VADProvider(VADProviderBase): # 如果之前有声音,但本次没有声音,且与上次有声音的时间差已经超过了静默阈值,则认为已经说完一句话 if conn.client_have_voice and not client_have_voice: - stop_duration = time.time() * 1000 - conn.last_activity_time + stop_duration = time.time() * 1000 - conn.vad_last_voice_time if stop_duration >= self.silence_threshold_ms: conn.client_voice_stop = True if client_have_voice: conn.client_have_voice = True - conn.last_activity_time = time.time() * 1000 + conn.vad_last_voice_time = time.time() * 1000 return client_have_voice except opuslib_next.OpusError as e: