From ed89c05245752bb631c2b1fb5d671b822756ce15 Mon Sep 17 00:00:00 2001 From: Sakura-RanChen <1908198662@qq.com> Date: Mon, 20 Jul 2026 14:48:26 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20intent=E9=98=BB=E5=A1=9E=E4=B8=BB?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/handle/intentHandler.py | 23 ++++++++++++++++--- .../providers/intent/intent_llm/intent_llm.py | 22 +++++++++++++----- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/main/xiaozhi-server/core/handle/intentHandler.py b/main/xiaozhi-server/core/handle/intentHandler.py index 4172653f..1a72d1d6 100644 --- a/main/xiaozhi-server/core/handle/intentHandler.py +++ b/main/xiaozhi-server/core/handle/intentHandler.py @@ -118,8 +118,17 @@ async def process_intent_result( 请根据以上信息回答用户的问题:{original_text}""" - response = conn.intent.replyResult(context_prompt, original_text) - speak_txt(conn, response) + # 使用异步调用避免阻塞事件循环,影响其他设备的音频播放 + try: + response = asyncio.run_coroutine_threadsafe( + conn.intent.replyResult(context_prompt, original_text), + conn.loop, + ).result() + except Exception as e: + conn.logger.bind(tag=TAG).error(f"LLM生成回复失败: {e}") + response = None + if response: + speak_txt(conn, response) conn.executor.submit(process_context_result) return True @@ -184,7 +193,15 @@ async def process_intent_result( elif result.action == Action.REQLLM: # 调用函数后再请求llm生成回复 text = result.result conn.dialogue.put(Message(role="tool", content=text)) - llm_result = conn.intent.replyResult(text, original_text) + # 使用异步调用避免阻塞事件循环,影响其他设备的音频播放 + try: + llm_result = asyncio.run_coroutine_threadsafe( + conn.intent.replyResult(text, original_text), + conn.loop, + ).result() + except Exception as e: + conn.logger.bind(tag=TAG).error(f"LLM生成回复失败: {e}") + llm_result = text if llm_result is None: llm_result = text speak_txt(conn, llm_result) diff --git a/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py b/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py index 669b21d3..cd150bc5 100644 --- a/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py +++ b/main/xiaozhi-server/core/providers/intent/intent_llm/intent_llm.py @@ -1,3 +1,4 @@ +import asyncio from typing import List, Dict, TYPE_CHECKING if TYPE_CHECKING: @@ -120,12 +121,18 @@ class IntentProvider(IntentProviderBase): ) return prompt - def replyResult(self, text: str, original_text: str): + async def replyResult(self, text: str, original_text: str): + """使用 asyncio.to_thread 避免阻塞事件循环""" try: - llm_result = self.llm.response_no_stream( + user_prompt = ( + "请根据以上内容,像人类一样说话的口吻回复用户,要求简洁,请直接返回结果。用户现在说:" + + original_text + ) + # 使用 to_thread 将同步阻塞调用放到线程池中执行,不阻塞事件循环 + llm_result = await asyncio.to_thread( + self.llm.response_no_stream, system_prompt=text, - user_prompt="请根据以上内容,像人类一样说话的口吻回复用户,要求简洁,请直接返回结果。用户现在说:" - + original_text, + user_prompt=user_prompt, ) return llm_result except Exception as e: @@ -207,8 +214,11 @@ class IntentProvider(IntentProviderBase): logger.bind(tag=TAG).debug(f"开始LLM意图识别调用, 模型: {model_info}") try: - intent = self.llm.response_no_stream( - system_prompt=prompt_music, user_prompt=user_prompt + # 使用 to_thread 将同步阻塞调用放到线程池中,避免阻塞事件循环 + intent = await asyncio.to_thread( + self.llm.response_no_stream, + system_prompt=prompt_music, + user_prompt=user_prompt, ) except Exception as e: logger.bind(tag=TAG).error(f"Error in intent detection LLM call: {e}") From 6e92d169ecebe6b29fd4e3f543a95851ad25d74a Mon Sep 17 00:00:00 2001 From: wengzh <1337326764@qq.com> Date: Mon, 20 Jul 2026 15:51:23 +0800 Subject: [PATCH 2/2] =?UTF-8?q?refactor(get=5Fnews=5Ffrom=5Fnewsnow):=20?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E6=B5=81=E5=BC=8F=E5=A4=84=E7=90=86=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E7=BD=91=E9=A1=B5=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将原有的直接转换响应内容改为流式读取字节流并传入参数,适配MarkItDown的convert_stream接口,优化大内容处理时的内存占用 --- .../plugins_func/functions/get_news_from_newsnow.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/main/xiaozhi-server/plugins_func/functions/get_news_from_newsnow.py b/main/xiaozhi-server/plugins_func/functions/get_news_from_newsnow.py index 8f0df016..631b3027 100644 --- a/main/xiaozhi-server/plugins_func/functions/get_news_from_newsnow.py +++ b/main/xiaozhi-server/plugins_func/functions/get_news_from_newsnow.py @@ -1,6 +1,7 @@ import random import httpx -from markitdown import MarkItDown +from io import BytesIO +from markitdown import MarkItDown, StreamInfo from config.logger import setup_logging from plugins_func.register import register_function, ToolType, ActionResponse, Action from typing import TYPE_CHECKING @@ -144,7 +145,14 @@ async def fetch_news_detail(url): # 使用MarkItDown清理HTML内容 md = MarkItDown(enable_plugins=False) - result = md.convert(response) + result = md.convert_stream( + BytesIO(response.content), + stream_info=StreamInfo( + mimetype="text/html", + extension=".html", + charset=response.encoding or "utf-8", + ), + ) # 获取清理后的文本内容 clean_text = result.text_content