From 4fc306bccf7c4018a8bd8592084627122d702536 Mon Sep 17 00:00:00 2001 From: Harold Date: Wed, 12 Nov 2025 15:00:39 +0800 Subject: [PATCH 1/5] fix(web-audio): Fix AudioWorklet recording and AudioContext state issues --- main/xiaozhi-server/test/test_page.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/main/xiaozhi-server/test/test_page.html b/main/xiaozhi-server/test/test_page.html index a6672dbc..b9fc5c85 100644 --- a/main/xiaozhi-server/test/test_page.html +++ b/main/xiaozhi-server/test/test_page.html @@ -1430,6 +1430,13 @@ }; log('使用AudioWorklet处理音频', 'success'); + + // 需要连接输出,否则不会触发处理 + // 我们创建一个静音通道 + const silent = audioContext.createGain(); + silent.gain.value = 0; + audioProcessor.connect(silent); + silent.connect(audioContext.destination); return { node: audioProcessor, type: 'worklet' }; } else { // 使用旧版ScriptProcessorNode作为回退方案 @@ -1604,6 +1611,11 @@ // 创建音频上下文和分析器 audioContext = getAudioContextInstance(); + // 浏览器出于安全和性能考虑,新创建的 AudioContext 默认处于 suspended 状态,必须显式调用 resume() 才会开始处理音频。 + if (audioContext.state === 'suspended') { + await audioContext.resume(); + } + // 创建音频处理器 const processorResult = await createAudioProcessor(); if (!processorResult) { From 8a4f786c0bbbd831f6ba630728a2ec37332856c2 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Thu, 13 Nov 2025 10:44:00 +0800 Subject: [PATCH 2/5] =?UTF-8?q?update:ragflow=E6=95=99=E7=A8=8B=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=88=B00.22.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/homeassistant-integration.md | 2 +- docs/ragflow-integration.md | 7 ++----- .../src/main/resources/db/changelog/202511131020.sql | 11 +++++++++++ .../resources/db/changelog/db.changelog-master.yaml | 9 ++++++++- .../core/providers/intent/intent_llm/intent_llm.py | 11 ++++++----- 6 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 main/manager-api/src/main/resources/db/changelog/202511131020.sql diff --git a/README.md b/README.md index bca5f9ee..c8c39df7 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ Websocket接口地址: wss://2662r3426b.vicp.fun/xiaozhi/v1/ | 声纹识别 | 支持多用户声纹注册、管理和识别,与ASR并行处理,实时识别说话人身份并传递给LLM进行个性化回应 | | 智能对话 | 支持多种LLM(大语言模型),实现智能对话 | | 视觉感知 | 支持多种VLLM(视觉大模型),实现多模态交互 | -| 意图识别 | 支持LLM意图识别、Function Call函数调用,提供插件化意图处理机制 | +| 意图识别 | 支持外挂的大模型意图识别、大模型自主函数调用,提供插件化意图处理机制 | | 记忆系统 | 支持本地短期记忆、mem0ai接口记忆,具备记忆总结功能 | | 知识库 | 支持RAGFlow知识库,让大模型判断需要调度知识库后再回答 | | 工具调用 | 支持客户端IOT协议、客户MCP协议、服务端MCP协议、MCP接入点协议、自定义工具函数 | diff --git a/docs/homeassistant-integration.md b/docs/homeassistant-integration.md index 7e69c229..c6e26ba6 100644 --- a/docs/homeassistant-integration.md +++ b/docs/homeassistant-integration.md @@ -97,7 +97,7 @@ http://homeassistant.local:8123 使用管理员账号,登录`智控台`。在`智能体管理`,找到你的智能体,再点击`配置角色`。 -将意图识别设置成`函数调用`或`LLM意图识别`。这时你会看到右侧有一个`编辑功能`。点击`编辑功能`按钮,会弹出`功能管理`的框。 +将意图识别设置成`外挂的大模型意图识别`或`大模型自主函数调用`。这时你会看到右侧有一个`编辑功能`。点击`编辑功能`按钮,会弹出`功能管理`的框。 在`功能管理`的框里,你需要勾选`HomeAssistant设备状态查询`和`HomeAssistant设备状态修改`。 diff --git a/docs/ragflow-integration.md b/docs/ragflow-integration.md index 5010cde3..6a969b48 100644 --- a/docs/ragflow-integration.md +++ b/docs/ragflow-integration.md @@ -90,12 +90,11 @@ FLUSH PRIVILEGES; 你需要在你电脑找一个文件夹,用来存放ragflow项目。例如我在`/home/system/xiaozhi`文件夹。 -你可以使用`git`命令,将ragflow项目下载到这个文件夹,本教程使用的是`2025年11月11日`提交的`dd5b8e2e1a877211d17aae5552d8895b1bca763d`版本进行安装部署。 +你可以使用`git`命令,将ragflow项目下载到这个文件夹,本教程使用的是`v0.22.0`版本进行安装部署。 ``` git clone https://ghfast.top/https://github.com/infiniflow/ragflow.git cd ragflow -git reset --hard dd5b8e2e1a877211d17aae5552d8895b1bca763d - +git checkout v0.22.0 ``` 下载完后,进入`docker`文件夹。 ``` shell @@ -158,8 +157,6 @@ services: 编辑`ragflow/docker`文件夹下的`.env`文件,找到以下配置,逐个搜索,逐个修改!逐个搜索,逐个修改! ``` env -# ragflow镜像 -RAGFLOW_IMAGE=infiniflow/ragflow@sha256:d9ff494d1bf72138ce6fe0eaf4962cf4bea471c8c266d12b8bfb9d10ac3a2f6e # 端口设置 SVR_WEB_HTTP_PORT=8008 # HTTP端口 SVR_WEB_HTTPS_PORT=8009 # HTTPS端口 diff --git a/main/manager-api/src/main/resources/db/changelog/202511131020.sql b/main/manager-api/src/main/resources/db/changelog/202511131020.sql new file mode 100644 index 00000000..1d19240d --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202511131020.sql @@ -0,0 +1,11 @@ +UPDATE `ai_model_config` SET +`doc_link` = 'https://github.com/infiniflow/ragflow/blob/main/README_zh.md', +`remark` = '详细部署教程参考:https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/ragflow-integration.md +部署成功,注冊登录后,点击右上角头像,获得RAGFlow的API KEY和API服务器地址。使用RAGFlow前请在Model Provider中添加模型和设置默认模型。' WHERE `id` = 'RAG_RAGFlow'; + +update `ai_model_config` set `model_name` = '外挂的大模型意图识别' where `id` = 'Intent_intent_llm'; +update `ai_model_config` set `model_name` = '大模型自主函数调用' where `id` = 'Intent_function_call'; + +update `ai_model_provider` set `name` = '外挂的大模型意图识别' , `fields` = '[{"key":"llm","label":"引用的LLM模型","type":"string"}]' where id = 'SYSTEM_Intent_intent_llm'; +update `ai_model_provider` set `name` = '大模型自主函数调用' where id = 'SYSTEM_Intent_function_call'; + diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index 326d6f57..c6f1a44e 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -415,4 +415,11 @@ databaseChangeLog: changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202510251150.sql \ No newline at end of file + path: classpath:db/changelog/202510251150.sql + - changeSet: + id: 202511131020 + author: hrz + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202511131020.sql \ No newline at end of file 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 8d426d08..73ab843a 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 @@ -55,7 +55,6 @@ class IntentProvider(IntentProviderBase): prompt = ( "【严格格式要求】你必须只能返回JSON格式,绝对不能返回任何自然语言!\n\n" "你是一个意图识别助手。请分析用户的最后一句话,判断用户意图并调用相应的函数。\n\n" - "【重要规则】以下类型的查询请直接返回result_for_context,无需调用函数:\n" "- 询问当前时间(如:现在几点、当前时间、查询时间等)\n" "- 询问今天日期(如:今天几号、今天星期几、今天是什么日期等)\n" @@ -202,7 +201,7 @@ class IntentProvider(IntentProviderBase): # 记录LLM调用完成时间 llm_time = time.time() - llm_start_time logger.bind(tag=TAG).debug( - f"LLM意图识别完成, 模型: {model_info}, 调用耗时: {llm_time:.4f}秒" + f"外挂的大模型意图识别完成, 模型: {model_info}, 调用耗时: {llm_time:.4f}秒" ) # 记录后处理开始时间 @@ -238,8 +237,10 @@ class IntentProvider(IntentProviderBase): # 处理不同类型的意图 if function_name == "result_for_context": # 处理基础信息查询,直接从context构建结果 - logger.bind(tag=TAG).info("检测到result_for_context意图,将使用上下文信息直接回答") - + logger.bind(tag=TAG).info( + "检测到result_for_context意图,将使用上下文信息直接回答" + ) + elif function_name == "continue_chat": # 处理普通对话 # 保留非工具相关的消息 @@ -249,7 +250,7 @@ class IntentProvider(IntentProviderBase): if msg.role not in ["tool", "function"] ] conn.dialogue.dialogue = clean_history - + else: # 处理函数调用 logger.bind(tag=TAG).info(f"检测到函数调用意图: {function_name}") From cd113a535166f12c082abe2d7528fc28631c0b04 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Thu, 13 Nov 2025 11:01:28 +0800 Subject: [PATCH 3/5] =?UTF-8?q?update:=E6=8F=92=E4=BB=B6=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E5=89=8D=EF=BC=8C=E4=B8=8D=E5=90=8C=E9=A2=9C=E8=89=B2=E7=9A=84?= =?UTF-8?q?=E7=82=B9=E6=98=93=E8=AE=A9=E4=BA=BA=E4=BA=A7=E7=94=9F=E8=AF=AF?= =?UTF-8?q?=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/FunctionDialog.vue | 29 +++++++++---------- main/manager-web/src/views/roleConfig.vue | 17 ++++------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/main/manager-web/src/components/FunctionDialog.vue b/main/manager-web/src/components/FunctionDialog.vue index c554a4a3..23adce78 100644 --- a/main/manager-web/src/components/FunctionDialog.vue +++ b/main/manager-web/src/components/FunctionDialog.vue @@ -13,7 +13,9 @@

{{ $t('functionDialog.unselectedFunctions') }}

- {{ $t('functionDialog.selectAll') }} + + {{ $t('functionDialog.selectAll') }} +
@@ -21,7 +23,7 @@
-
+
{{ func.name }}
@@ -36,7 +38,9 @@

{{ $t('functionDialog.selectedFunctions') }}

- {{ $t('functionDialog.selectAll') }} + + {{ $t('functionDialog.selectAll') }} +
@@ -44,7 +48,7 @@
-
+
{{ func.name }}
@@ -57,7 +61,9 @@
-

{{ $t('functionDialog.paramConfig') }} - {{ currentFunction.name }}

+

+ {{ $t('functionDialog.paramConfig') }} - {{ currentFunction.name }} +

@@ -119,8 +125,8 @@
@@ -191,10 +197,6 @@ export default { selectedNames: [], currentFunction: null, modifiedFunctions: {}, - functionColorMap: [ - '#FF6B6B', '#4ECDC4', '#45B7D1', - '#96CEB4', '#FFEEAD', '#D4A5A5', '#A2836E' - ], tempFunctions: {}, // 添加一个标志位来跟踪是否已经保存 hasSaved: false, @@ -405,10 +407,6 @@ export default { // 通知父组件对话框已关闭且已保存 this.$emit('dialog-closed', true); }, - getFunctionColor(name) { - const hash = [...name].reduce((acc, char) => acc + char.charCodeAt(0), 0); - return this.functionColorMap[hash % this.functionColorMap.length]; - }, fieldRemark(field) { let description = (field && field.label) ? field.label : ''; if (field.default) { @@ -527,6 +525,7 @@ export default { flex-shrink: 0; width: 8px; height: 8px; + background-color: #5778ff; margin-right: 8px; border-radius: 50%; } diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index a0f89503..8e0eee08 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -104,7 +104,7 @@
功能名称: {{ func.name }}
-
+
{{ getFunctionDisplayChar(func.name) }}
@@ -189,10 +189,6 @@ export default { voiceOptions: [], showFunctionDialog: false, currentFunctions: [], - functionColorMap: [ - '#FF6B6B', '#4ECDC4', '#45B7D1', - '#96CEB4', '#FFEEAD', '#D4A5A5', '#A2836E' - ], allFunctions: [], originalFunctions: [], } @@ -428,20 +424,16 @@ export default { } }); }, - getFunctionColor(name) { - const hash = [...name].reduce((acc, char) => acc + char.charCodeAt(0), 0); - return this.functionColorMap[hash % this.functionColorMap.length]; - }, getFunctionDisplayChar(name) { if (!name || name.length === 0) return ''; - + for (let i = 0; i < name.length; i++) { const char = name[i]; if (/[\u4e00-\u9fa5a-zA-Z0-9]/.test(char)) { return char; } } - + // 如果没有找到有效字符,返回第一个字符 return name.charAt(0); }, @@ -768,11 +760,12 @@ export default { display: inline-flex; align-items: center; justify-content: center; - color: white; + color: #5778ff; font-weight: bold; font-size: 12px; margin-right: 8px; position: relative; + background-color: #e6ebff; } ::v-deep .el-form-item__label { From 48d72e373e1a9b705d35f9176f18d8cecc73b3a2 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Thu, 13 Nov 2025 12:15:54 +0800 Subject: [PATCH 4/5] Update ragflow-integration.md --- docs/ragflow-integration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ragflow-integration.md b/docs/ragflow-integration.md index 6a969b48..c2cd20f5 100644 --- a/docs/ragflow-integration.md +++ b/docs/ragflow-integration.md @@ -170,7 +170,7 @@ MYSQL_DBNAME=rag_flow # 数据库名称 # Redis配置 - 修改为您本地Redis的信息 REDIS_HOST=host.docker.internal # 使用host.docker.internal让容器访问主机服务 REDIS_PORT=6379 # 本地Redis端口 -REDIS_PASSWORD= # 如果你的Redis没有设置密码,这里填写None,否则填写密码 +REDIS_PASSWORD= # 如果你的Redis没有设置密码,就按这样子填写,否则填写密码 ``` 注意,如果你的Redis没有设置密码,还要修改`ragflow/docker`文件夹下`service_conf.yaml.template`,将`infini_rag_flow`替换成空字符串。 @@ -256,4 +256,4 @@ docker-compose -f docker-compose.yml up -d # 第三步 让小智使用ragflow知识库 登录到智控台。在顶部导航栏中,点击`智能体`,找到你要配置的智能体,点击`配置角色`按钮。 -在意图识别左侧,点击`编辑功能`按钮,弹出一个弹框。在弹框中选择你要添加的知识库。保存即可。 \ No newline at end of file +在意图识别左侧,点击`编辑功能`按钮,弹出一个弹框。在弹框中选择你要添加的知识库。保存即可。 From 578ed62d1835cbc435339a2a767a31068b1d5101 Mon Sep 17 00:00:00 2001 From: shiyin Date: Thu, 13 Nov 2025 14:28:21 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E7=81=AB=E5=B1=B1=E5=8F=8C=E6=B5=81?= =?UTF-8?q?=E5=BC=8FTTS=E6=97=A5=E5=BF=97bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py b/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py index 831e2393..4c761ac2 100644 --- a/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py +++ b/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py @@ -240,7 +240,7 @@ class TTSProvider(TTSProviderBase): self.conn.sentence_id = uuid.uuid4().hex logger.bind(tag=TAG).debug(f"自动生成新的 会话ID: {self.conn.sentence_id}") - logger.bind(tag=TAG).debu("开始启动TTS会话...") + logger.bind(tag=TAG).debug("开始启动TTS会话...") future = asyncio.run_coroutine_threadsafe( self.start_session(self.conn.sentence_id), loop=self.conn.loop,