From 6120d49a35ae43b088948ab7f0612ff6e711e190 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Wed, 3 Dec 2025 22:49:32 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix:=E8=BF=87=E6=BB=A48000=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E4=BD=BF=E7=94=A8https=E8=AE=BF=E9=97=AE=E6=97=B6?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/websocket_server.py | 29 +++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/main/xiaozhi-server/core/websocket_server.py b/main/xiaozhi-server/core/websocket_server.py index 9cbbbe19..168b436e 100644 --- a/main/xiaozhi-server/core/websocket_server.py +++ b/main/xiaozhi-server/core/websocket_server.py @@ -1,8 +1,35 @@ import asyncio -import json +import logging import websockets from config.logger import setup_logging + + +class SuppressInvalidHandshakeFilter(logging.Filter): + """过滤掉无效握手错误日志(如HTTPS访问WS端口)""" + + def filter(self, record): + msg = record.getMessage() + suppress_keywords = [ + "opening handshake failed", + "did not receive a valid HTTP request", + "connection closed while reading HTTP request", + "line without CRLF", + ] + return not any(keyword in msg for keyword in suppress_keywords) + + +def _setup_websockets_logger(): + """配置 websockets 相关的所有 logger,过滤无效握手错误""" + filter_instance = SuppressInvalidHandshakeFilter() + for logger_name in ["websockets", "websockets.server", "websockets.client"]: + logger = logging.getLogger(logger_name) + logger.addFilter(filter_instance) + + +_setup_websockets_logger() + + from core.connection import ConnectionHandler from config.config_loader import get_config_from_api_async from core.auth import AuthManager, AuthenticationError From f3580119000bf71a9e8c49409ebe0ef6e54044b3 Mon Sep 17 00:00:00 2001 From: shiyin Date: Thu, 4 Dec 2025 18:32:57 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=8E=A5=E5=8F=A3,=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E7=A0=81=E6=AD=BB=E5=BE=AA=E7=8E=AFBUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xiaozhi/modules/device/controller/DeviceController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java index ff6069bf..78a17b02 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java @@ -72,10 +72,12 @@ public class DeviceController { return new Result().error(ErrorCode.MCA_NOT_NULL); } // 生成六位验证码 - String code = String.valueOf(Math.random()).substring(2, 8); - String key = RedisKeys.getDeviceCaptchaKey(code); + String code; + String key; String existsMac = null; do { + code = String.valueOf(Math.random()).substring(2, 8); + key = RedisKeys.getDeviceCaptchaKey(code); existsMac = (String) redisUtils.get(key); } while (StringUtils.isNotBlank(existsMac)); From d3d329bd4313b2e26640706fb2adf8c0db2ae62c Mon Sep 17 00:00:00 2001 From: Sakura-RanChen <1908198662@qq.com> Date: Thu, 4 Dec 2025 18:45:49 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20=E7=8A=B6=E6=80=81=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/handle/sendAudioHandle.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/xiaozhi-server/core/handle/sendAudioHandle.py b/main/xiaozhi-server/core/handle/sendAudioHandle.py index 14f43232..ea952fbe 100644 --- a/main/xiaozhi-server/core/handle/sendAudioHandle.py +++ b/main/xiaozhi-server/core/handle/sendAudioHandle.py @@ -116,6 +116,7 @@ async def _sendAudio_single(conn, opus_packet, send_delay, frame_duration=60): if packet_count < pre_buffer_count or send_delay > 0: # 预缓冲阶段或固定延迟模式,直接发送 await _do_send_audio(conn, opus_packet, flow_control, frame_duration) + conn.client_is_speaking = True if send_delay > 0 and packet_count >= pre_buffer_count: await asyncio.sleep(send_delay) @@ -127,6 +128,7 @@ async def _sendAudio_single(conn, opus_packet, send_delay, frame_duration=60): await _do_send_audio(conn, packet, flow_control, frame_duration) await rate_controller.check_queue(send_callback) + conn.client_is_speaking = True # 更新流控状态 flow_control["packet_count"] += 1 From 5f229351c8fae7b1afa558175b0b54b5e17ce34b Mon Sep 17 00:00:00 2001 From: rainv123 <2148537152@qq.com> Date: Fri, 5 Dec 2025 14:35:53 +0800 Subject: [PATCH 4/6] =?UTF-8?q?uptate:=E5=A2=9E=E5=8A=A0=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/controller/LoginController.java | 33 +- .../resources/db/changelog/202512031513.sql | 6 + .../db/changelog/db.changelog-master.yaml | 8 + .../manager-web/src/components/DeviceItem.vue | 12 +- .../src/components/FunctionDialog.vue | 24 +- main/manager-web/src/components/HeaderBar.vue | 39 +- main/manager-web/src/i18n/de.js | 31 + main/manager-web/src/i18n/en.js | 31 + main/manager-web/src/i18n/vi.js | 31 + main/manager-web/src/i18n/zh_CN.js | 31 + main/manager-web/src/i18n/zh_TW.js | 31 + main/manager-web/src/main.js | 1 + main/manager-web/src/router/index.js | 21 +- main/manager-web/src/utils/featureManager.js | 340 ++++++++++ .../src/views/FeatureManagement.vue | 592 ++++++++++++++++++ main/manager-web/src/views/home.vue | 28 +- main/manager-web/src/views/login.vue | 8 + main/manager-web/src/views/roleConfig.vue | 35 +- 18 files changed, 1271 insertions(+), 31 deletions(-) create mode 100644 main/manager-api/src/main/resources/db/changelog/202512031513.sql create mode 100644 main/manager-web/src/utils/featureManager.js create mode 100644 main/manager-web/src/views/FeatureManagement.vue diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java index a008c25b..7262a7c8 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java @@ -41,6 +41,7 @@ import xiaozhi.modules.sys.service.SysDictDataService; import xiaozhi.modules.sys.service.SysParamsService; import xiaozhi.modules.sys.service.SysUserService; import xiaozhi.modules.sys.vo.SysDictDataItem; +import xiaozhi.common.utils.JsonUtils; /** * 登录控制层 @@ -89,13 +90,13 @@ public class LoginController { @Operation(summary = "登录") public Result login(@RequestBody LoginDTO login) { String password = login.getPassword(); - + // 使用工具类解密并验证验证码 String actualPassword = Sm2DecryptUtil.decryptAndValidateCaptcha( password, login.getCaptchaId(), captchaService, sysParamsService); - + login.setPassword(actualPassword); - + // 按照用户名获取用户 SysUserDTO userDTO = sysUserService.getByUsername(login.getUsername()); // 判断用户是否存在 @@ -108,8 +109,6 @@ public class LoginController { } return sysUserTokenService.createToken(userDTO.getId()); } - - @PostMapping("/register") @Operation(summary = "注册") @@ -117,15 +116,15 @@ public class LoginController { if (!sysUserService.getAllowUserRegister()) { throw new RenException(ErrorCode.USER_REGISTER_DISABLED); } - + String password = login.getPassword(); - + // 使用工具类解密并验证验证码 String actualPassword = Sm2DecryptUtil.decryptAndValidateCaptcha( password, login.getCaptchaId(), captchaService, sysParamsService); - + login.setPassword(actualPassword); - + // 是否开启手机注册 Boolean isMobileRegister = sysParamsService .getValueObject(Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class); @@ -204,11 +203,11 @@ public class LoginController { } String password = dto.getPassword(); - + // 使用工具类解密并验证验证码 String actualPassword = Sm2DecryptUtil.decryptAndValidateCaptcha( password, dto.getCaptchaId(), captchaService, sysParamsService); - + dto.setPassword(actualPassword); sysUserService.changePasswordDirectly(userDTO.getId(), dto.getPassword()); @@ -229,7 +228,7 @@ public class LoginController { config.put("beianIcpNum", sysParamsService.getValue(Constant.SysBaseParam.BEIAN_ICP_NUM.getValue(), true)); config.put("beianGaNum", sysParamsService.getValue(Constant.SysBaseParam.BEIAN_GA_NUM.getValue(), true)); config.put("name", sysParamsService.getValue(Constant.SysBaseParam.SERVER_NAME.getValue(), true)); - + // SM2公钥 String publicKey = sysParamsService.getValue(Constant.SM2_PUBLIC_KEY, true); if (StringUtils.isBlank(publicKey)) { @@ -237,6 +236,16 @@ public class LoginController { } config.put("sm2PublicKey", publicKey); + // 获取system-web.menu参数配置 + try { + String menuConfig = sysParamsService.getValue("system-web.menu", false); + if (StringUtils.isNotBlank(menuConfig)) { + config.put("systemWebMenu", JsonUtils.parseObject(menuConfig, Object.class)); + } + } catch (Exception e) { + log.warn("获取system-web.menu参数配置失败: {}", e.getMessage()); + } + return new Result>().ok(config); } } \ No newline at end of file diff --git a/main/manager-api/src/main/resources/db/changelog/202512031513.sql b/main/manager-api/src/main/resources/db/changelog/202512031513.sql new file mode 100644 index 00000000..10d93873 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202512031513.sql @@ -0,0 +1,6 @@ +-- 添加系统功能菜单配置参数 +delete from `sys_params` where param_code = 'system-web.menu'; + +-- 添加系统功能菜单配置参数 +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES +(600, 'system-web.menu', '{"voiceprintRecognition":{"name":"feature.voiceprintRecognition.name","enabled":true,"description":"feature.voiceprintRecognition.description"},"voiceClone":{"name":"feature.voiceClone.name","enabled":true,"description":"feature.voiceClone.description"},"knowledgeBase":{"name":"feature.knowledgeBase.name","enabled":false,"description":"feature.knowledgeBase.description"},"mcpAccessPoint":{"name":"feature.mcpAccessPoint.name","enabled":true,"description":"feature.mcpAccessPoint.description"},"vad":{"name":"feature.vad.name","enabled":true,"description":"feature.vad.description"},"asr":{"name":"feature.asr.name","enabled":true,"description":"feature.asr.description"}}', 'json', 1, '系统功能菜单配置'); \ No newline at end of file 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 3c14eb7f..bc6f8526 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 @@ -423,3 +423,11 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202511131023.sql + - changeSet: + id: 202512031513 + author: hrz + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202512031513.sql + diff --git a/main/manager-web/src/components/DeviceItem.vue b/main/manager-web/src/components/DeviceItem.vue index bfbbb97f..c29d3243 100644 --- a/main/manager-web/src/components/DeviceItem.vue +++ b/main/manager-web/src/components/DeviceItem.vue @@ -23,7 +23,7 @@
{{ $t('home.configureRole') }}
-
+
{{ $t('home.voiceprintRecognition') }}
@@ -49,7 +49,15 @@ import i18n from '@/i18n'; export default { name: 'DeviceItem', props: { - device: { type: Object, required: true } + device: { type: Object, required: true }, + featureStatus: { + type: Object, + default: () => ({ + voiceprintRecognition: false, + voiceClone: false, + knowledgeBase: false + }) + } }, data() { return { switchValue: false } diff --git a/main/manager-web/src/components/FunctionDialog.vue b/main/manager-web/src/components/FunctionDialog.vue index 23adce78..076cfa9f 100644 --- a/main/manager-web/src/components/FunctionDialog.vue +++ b/main/manager-web/src/components/FunctionDialog.vue @@ -106,7 +106,7 @@
-
+
@@ -171,6 +171,7 @@ + + \ No newline at end of file diff --git a/main/manager-web/src/views/home.vue b/main/manager-web/src/views/home.vue index 01cf74fb..fea5af89 100644 --- a/main/manager-web/src/views/home.vue +++ b/main/manager-web/src/views/home.vue @@ -39,8 +39,9 @@
@@ -61,6 +62,7 @@ import ChatHistoryDialog from '@/components/ChatHistoryDialog.vue'; import DeviceItem from '@/components/DeviceItem.vue'; import HeaderBar from '@/components/HeaderBar.vue'; import VersionFooter from '@/components/VersionFooter.vue'; +import featureManager from '@/utils/featureManager'; export default { name: 'HomePage', @@ -76,15 +78,33 @@ export default { skeletonCount: localStorage.getItem('skeletonCount') || 8, showChatHistory: false, currentAgentId: '', - currentAgentName: '' + currentAgentName: '', + // 功能状态 + featureStatus: { + voiceprintRecognition: false, + voiceClone: false, + knowledgeBase: false + } } }, - mounted() { + async mounted() { this.fetchAgentList(); + await this.loadFeatureStatus(); }, methods: { + // 加载功能状态 + async loadFeatureStatus() { + await featureManager.waitForInitialization(); + const config = featureManager.getConfig(); + this.featureStatus = { + voiceprintRecognition: config.voiceprintRecognition, + voiceClone: config.voiceClone, + knowledgeBase: config.knowledgeBase + }; + }, + showAddDialog() { this.addDeviceDialogVisible = true }, diff --git a/main/manager-web/src/views/login.vue b/main/manager-web/src/views/login.vue index 9d56fdc5..cdcf3754 100644 --- a/main/manager-web/src/views/login.vue +++ b/main/manager-web/src/views/login.vue @@ -156,6 +156,7 @@ import VersionFooter from "@/components/VersionFooter.vue"; import i18n, { changeLanguage } from "@/i18n"; import { getUUID, goToPage, showDanger, showSuccess, sm2Encrypt, validateMobile } from "@/utils"; import { mapState } from "vuex"; +import featureManager from "@/utils/featureManager"; export default { name: "login", @@ -214,6 +215,13 @@ export default { this.$store.dispatch("fetchPubConfig").then(() => { // 根据配置决定默认登录方式 this.isMobileLogin = this.enableMobileRegister; + + // pub-config接口调用完成后,重新初始化featureManager以确保使用最新的配置 + featureManager.waitForInitialization().then(() => { + console.log('featureManager重新初始化完成,使用pub-config配置'); + }).catch(error => { + console.warn('featureManager重新初始化失败:', error); + }); }); }, methods: { diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index a0baf371..c9ea518c 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -107,7 +107,11 @@
- +
- +
From 68b539db15f5266dadb2d72eb5fcf9e93827ed4f Mon Sep 17 00:00:00 2001 From: rainv123 <2148537152@qq.com> Date: Fri, 5 Dec 2025 15:29:28 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/security/controller/LoginController.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java index 7262a7c8..19bc2944 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java @@ -237,13 +237,9 @@ public class LoginController { config.put("sm2PublicKey", publicKey); // 获取system-web.menu参数配置 - try { - String menuConfig = sysParamsService.getValue("system-web.menu", false); - if (StringUtils.isNotBlank(menuConfig)) { - config.put("systemWebMenu", JsonUtils.parseObject(menuConfig, Object.class)); - } - } catch (Exception e) { - log.warn("获取system-web.menu参数配置失败: {}", e.getMessage()); + String menuConfig = sysParamsService.getValue("system-web.menu", true); + if (StringUtils.isNotBlank(menuConfig)) { + config.put("systemWebMenu", JsonUtils.parseObject(menuConfig, Object.class)); } return new Result>().ok(config); From 2ece3f399bae820b92178639b4e07b93c88b799d Mon Sep 17 00:00:00 2001 From: rainv123 <2148537152@qq.com> Date: Fri, 5 Dec 2025 15:39:05 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E6=94=B9=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E7=8A=B6=E6=80=81=E4=B8=BAfalse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/db/changelog/202512031513.sql | 6 ------ .../src/main/resources/db/changelog/202512031514.sql | 6 ++++++ .../main/resources/db/changelog/db.changelog-master.yaml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 main/manager-api/src/main/resources/db/changelog/202512031513.sql create mode 100644 main/manager-api/src/main/resources/db/changelog/202512031514.sql diff --git a/main/manager-api/src/main/resources/db/changelog/202512031513.sql b/main/manager-api/src/main/resources/db/changelog/202512031513.sql deleted file mode 100644 index 10d93873..00000000 --- a/main/manager-api/src/main/resources/db/changelog/202512031513.sql +++ /dev/null @@ -1,6 +0,0 @@ --- 添加系统功能菜单配置参数 -delete from `sys_params` where param_code = 'system-web.menu'; - --- 添加系统功能菜单配置参数 -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES -(600, 'system-web.menu', '{"voiceprintRecognition":{"name":"feature.voiceprintRecognition.name","enabled":true,"description":"feature.voiceprintRecognition.description"},"voiceClone":{"name":"feature.voiceClone.name","enabled":true,"description":"feature.voiceClone.description"},"knowledgeBase":{"name":"feature.knowledgeBase.name","enabled":false,"description":"feature.knowledgeBase.description"},"mcpAccessPoint":{"name":"feature.mcpAccessPoint.name","enabled":true,"description":"feature.mcpAccessPoint.description"},"vad":{"name":"feature.vad.name","enabled":true,"description":"feature.vad.description"},"asr":{"name":"feature.asr.name","enabled":true,"description":"feature.asr.description"}}', 'json', 1, '系统功能菜单配置'); \ No newline at end of file diff --git a/main/manager-api/src/main/resources/db/changelog/202512031514.sql b/main/manager-api/src/main/resources/db/changelog/202512031514.sql new file mode 100644 index 00000000..adfff855 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202512031514.sql @@ -0,0 +1,6 @@ +-- 添加系统功能菜单配置参数 +delete from `sys_params` where param_code = 'system-web.menu'; + +-- 添加系统功能菜单配置参数 +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES +(600, 'system-web.menu', '{"voiceprintRecognition":{"name":"feature.voiceprintRecognition.name","enabled":false,"description":"feature.voiceprintRecognition.description"},"voiceClone":{"name":"feature.voiceClone.name","enabled":false,"description":"feature.voiceClone.description"},"knowledgeBase":{"name":"feature.knowledgeBase.name","enabled":false,"description":"feature.knowledgeBase.description"},"mcpAccessPoint":{"name":"feature.mcpAccessPoint.name","enabled":false,"description":"feature.mcpAccessPoint.description"},"vad":{"name":"feature.vad.name","enabled":false,"description":"feature.vad.description"},"asr":{"name":"feature.asr.name","enabled":false,"description":"feature.asr.description"}}', 'json', 1, '系统功能菜单配置'); \ No newline at end of file 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 bc6f8526..c929f760 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 @@ -424,10 +424,10 @@ databaseChangeLog: encoding: utf8 path: classpath:db/changelog/202511131023.sql - changeSet: - id: 202512031513 + id: 202512031514 author: hrz changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202512031513.sql + path: classpath:db/changelog/202512031514.sql