diff --git a/docs/ali-sms-integration.md b/docs/ali-sms-integration.md index 1e3f7f91..1be27787 100644 --- a/docs/ali-sms-integration.md +++ b/docs/ali-sms-integration.md @@ -40,5 +40,5 @@ 2、开启允许非管理员用户可注册,将参数`server.allow_user_register`设置成`true` -3、开启手机注册功能,将参数`system.enable_mobile_register`设置成`true` +3、开启手机注册功能,将参数`server.enable_mobile_register`设置成`true` ![步骤](images/alisms/sms-32.png) \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java index c6ec6761..b3c036ee 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java +++ b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java @@ -118,29 +118,17 @@ public interface Constant { enum SysBaseParam { /** - * 系统全称 + * ICP备案号 */ - SYS_NAME("SYS_NAME"), + BEIAN_ICP_NUM("server.beian_icp_num"), /** - * 系统简称 + * GA备案号 */ - SYS_SHORT_NAME("SYS_SHORT_NAME"), + BEIAN_GA_NUM("server.beian_ga_num"), /** - * 系统描述 + * 系统名称 */ - SYS_DES("SYS_DES"), - /** - * 登录失败几次锁定 - */ - LOGIN_LOCK_COUNT("LOGIN_LOCK_COUNT"), - /** - * 账号失败锁定分钟数 - */ - LOGIN_LOCK_TIME("LOGIN_LOCK_TIME"), - /** - * TOKEN强验证 - */ - SYS_TOKEN_SECURITY("SYS_TOKEN_SECURITY"); + SERVER_NAME("server.name"); private String value; @@ -176,11 +164,11 @@ public interface Constant { /** * 单号码最大短信发送条数 */ - SYSTEM_SMS_MAX_SEND_COUNT("system.sms.max_send_count"), + SERVER_SMS_MAX_SEND_COUNT("server.sms_max_send_count"), /** * 是否开启手机注册 */ - SYSTEM_ENABLE_MOBILE_REGISTER("system.enable_mobile_register"); + SERVER_ENABLE_MOBILE_REGISTER("server.enable_mobile_register"); private String value; @@ -245,4 +233,24 @@ public interface Constant { * 无效固件URL */ String INVALID_FIRMWARE_URL = "http://xiaozhi.server.com:8002/xiaozhi/otaMag/download/NOT_ACTIVATED_FIRMWARE_THIS_IS_A_INVALID_URL"; + + /** + * 字典类型 + */ + enum DictType { + /** + * 手机区号 + */ + MOBILE_AREA("MOBILE_AREA"); + + private String value; + + DictType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } } \ No newline at end of file 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 47fd7b1b..0215cf7e 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 @@ -1,6 +1,7 @@ package xiaozhi.modules.security.controller; import java.io.IOException; +import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -70,7 +71,7 @@ public class LoginController { throw new RenException("图形验证码错误"); } Boolean isMobileRegister = sysParamsService - .getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class); + .getValueObject(Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class); if (!isMobileRegister) { throw new RenException("没有开启手机注册,没法使用短信验证码功能"); } @@ -108,7 +109,7 @@ public class LoginController { } // 是否开启手机注册 Boolean isMobileRegister = sysParamsService - .getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class); + .getValueObject(Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class); boolean validate; if (isMobileRegister) { // 验证用户是否是手机号码 @@ -165,7 +166,7 @@ public class LoginController { public Result retrievePassword(@RequestBody RetrievePasswordDTO dto) { // 是否开启手机注册 Boolean isMobileRegister = sysParamsService - .getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class); + .getValueObject(Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class); if (!isMobileRegister) { throw new RenException("没有开启手机注册,没法使用找回密码功能"); } @@ -198,11 +199,15 @@ public class LoginController { public Result> pubConfig() { Map config = new HashMap<>(); config.put("enableMobileRegister", sysParamsService - .getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class)); + .getValueObject(Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class)); config.put("version", Constant.VERSION); + config.put("year", "©" + Calendar.getInstance().get(Calendar.YEAR)); config.put("allowUserRegister", sysUserService.getAllowUserRegister()); - List list = sysDictDataService.getDictDataByType("MOBILE_AREA"); + List list = sysDictDataService.getDictDataByType(Constant.DictType.MOBILE_AREA.getValue()); config.put("mobileAreaList", list); + 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)); return new Result>().ok(config); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/service/impl/CaptchaServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/security/service/impl/CaptchaServiceImpl.java index c6f8f490..e823d70e 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/security/service/impl/CaptchaServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/security/service/impl/CaptchaServiceImpl.java @@ -101,7 +101,7 @@ public class CaptchaServiceImpl implements CaptchaService { // 获取最大发送次数限制 Integer maxSendCount = sysParamsService.getValueObject( - Constant.SysMSMParam.SYSTEM_SMS_MAX_SEND_COUNT.getValue(), + Constant.SysMSMParam.SERVER_SMS_MAX_SEND_COUNT.getValue(), Integer.class); if (maxSendCount == null) { maxSendCount = 5; // 默认值 diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysParamsController.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysParamsController.java index 9b80c76c..e1774280 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysParamsController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysParamsController.java @@ -59,7 +59,7 @@ public class SysParamsController { @Parameter(name = Constant.LIMIT, description = "每页显示记录数", in = ParameterIn.QUERY, required = true, ref = "int"), @Parameter(name = Constant.ORDER_FIELD, description = "排序字段", in = ParameterIn.QUERY, ref = "String"), @Parameter(name = Constant.ORDER, description = "排序方式,可选值(asc、desc)", in = ParameterIn.QUERY, ref = "String"), - @Parameter(name = "paramCode", description = "参数编码", in = ParameterIn.QUERY, ref = "String") + @Parameter(name = "paramCode", description = "参数编码或参数备注", in = ParameterIn.QUERY, ref = "String") }) @RequiresPermissions("sys:role:superAdmin") public Result> page(@Parameter(hidden = true) @RequestParam Map params) { diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java index a72b94f4..0ba595c0 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java @@ -52,7 +52,9 @@ public class SysParamsServiceImpl extends BaseServiceImpl wrapper = new QueryWrapper<>(); wrapper.eq("param_type", 1); - wrapper.like(StringUtils.isNotBlank(paramCode), "param_code", paramCode); + wrapper.nested(StringUtils.isNotBlank(paramCode),i->i.like("param_code", paramCode) + .or() + .like("remark", paramCode)); return wrapper; } diff --git a/main/manager-api/src/main/resources/db/changelog/202505141132.sql b/main/manager-api/src/main/resources/db/changelog/202505182234.sql similarity index 84% rename from main/manager-api/src/main/resources/db/changelog/202505141132.sql rename to main/manager-api/src/main/resources/db/changelog/202505182234.sql index 4e60a350..3873e5d4 100644 --- a/main/manager-api/src/main/resources/db/changelog/202505141132.sql +++ b/main/manager-api/src/main/resources/db/changelog/202505182234.sql @@ -1,15 +1,21 @@ -- 添加手机短信注册功能的需要的参数 -delete from sys_params where id in (601, 602, 610, 611, 612, 613); +delete from sys_params where id in (108, 109, 110, 111, 112, 113, 114, 115); +delete from sys_params where id in (610, 611, 612, 613); INSERT INTO sys_params (id, param_code, param_value, value_type, param_type, remark, creator, create_date, updater, update_date) VALUES -(601, 'system.enable_mobile_register', 'false', 'boolean', 1, '是否开启手机注册', NULL, NULL, NULL, NULL), -(602, 'system.sms.max_send_count', '10', 'number', 1, '单号码单日最大短信发送条数', NULL, NULL, NULL, NULL), +(108, 'server.name', 'xiaozhi-esp32-server', 'string', 1, '系统名称', NULL, NULL, NULL, NULL), +(109, 'server.beian_icp_num', 'null', 'string', 1, 'icp备案号,填写null则不设置', NULL, NULL, NULL, NULL), +(110, 'server.beian_ga_num', 'null', 'string', 1, '公安备案号,填写null则不设置', NULL, NULL, NULL, NULL), +(111, 'server.enable_mobile_register', 'false', 'boolean', 1, '是否开启手机注册', NULL, NULL, NULL, NULL), +(112, 'server.sms_max_send_count', '10', 'number', 1, '单号码单日最大短信发送条数', NULL, NULL, NULL, NULL), (610, 'aliyun.sms.access_key_id', '', 'string', 1, '阿里云平台access_key', NULL, NULL, NULL, NULL), (611, 'aliyun.sms.access_key_secret', '', 'string', 1, '阿里云平台access_key_secret', NULL, NULL, NULL, NULL), (612, 'aliyun.sms.sign_name', '', 'string', 1, '阿里云短信签名', NULL, NULL, NULL, NULL), (613, 'aliyun.sms.sms_code_template_code', '', 'string', 1, '阿里云短信模板', NULL, NULL, NULL, NULL); +update sys_params set remark = '是否允许管理员以外的人注册' where param_code = 'server.allow_user_register'; + -- 增加手机区域字典 -- 插入固件类型字典类型 delete from `sys_dict_type` where `id` = 102; 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 30dbd888..b52dd24c 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 @@ -114,13 +114,6 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202505091409.sql - - changeSet: - id: 202505141132 - author: zjy - changes: - - sqlFile: - encoding: utf8 - path: classpath:db/changelog/202505141132.sql - changeSet: id: 202505091555 author: whosmyqueen @@ -149,3 +142,10 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202505142037.sql + - changeSet: + id: 202505182234 + author: amen + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202505182234.sql \ No newline at end of file diff --git a/main/manager-web/src/components/VersionFooter.vue b/main/manager-web/src/components/VersionFooter.vue index 6226bcc0..ea34b1bb 100644 --- a/main/manager-web/src/components/VersionFooter.vue +++ b/main/manager-web/src/components/VersionFooter.vue @@ -1,23 +1,74 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/main/manager-web/src/store/index.js b/main/manager-web/src/store/index.js index 7a33ed61..08dd5042 100644 --- a/main/manager-web/src/store/index.js +++ b/main/manager-web/src/store/index.js @@ -13,6 +13,8 @@ export default new Vuex.Store({ isSuperAdmin: false, // 添加superAdmin状态 pubConfig: { // 添加公共配置存储 version: '', + beianIcpNum: 'null', + beianGaNum: 'null', allowUserRegister: false } }, diff --git a/main/manager-web/src/views/ParamsManagement.vue b/main/manager-web/src/views/ParamsManagement.vue index afb0dc1d..71d0866b 100644 --- a/main/manager-web/src/views/ParamsManagement.vue +++ b/main/manager-web/src/views/ParamsManagement.vue @@ -5,7 +5,7 @@

参数管理

- 搜索
diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index c1ca2dbb..05756cd7 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -411,7 +411,7 @@ LLM: base_url: https://host/api/v1 # 你可以在这里找到你的api_key # https://cloud.tryfastgpt.ai/account/apikey - api_key: fastgpt-xxx + api_key: 你的fastgpt密钥 variables: k: "v" k2: "v2" diff --git a/main/xiaozhi-server/config/config_loader.py b/main/xiaozhi-server/config/config_loader.py index 35802a67..f14e4aa3 100644 --- a/main/xiaozhi-server/config/config_loader.py +++ b/main/xiaozhi-server/config/config_loader.py @@ -82,6 +82,8 @@ def ensure_directories(config): # ASR/TTS模块输出目录 for module in ["ASR", "TTS"]: + if config.get(module) is None: + continue for provider in config.get(module, {}).values(): output_dir = provider.get("output_dir", "") if output_dir: @@ -93,6 +95,10 @@ def ensure_directories(config): selected_provider = selected_modules.get(module_type) if not selected_provider: continue + if config.get(module) is None: + continue + if config.get(selected_provider) is None: + continue provider_config = config.get(module_type, {}).get(selected_provider, {}) output_dir = provider_config.get("output_dir") if output_dir: diff --git a/main/xiaozhi-server/performance_tester.py b/main/xiaozhi-server/performance_tester.py index 38daea00..80503166 100644 --- a/main/xiaozhi-server/performance_tester.py +++ b/main/xiaozhi-server/performance_tester.py @@ -1,15 +1,17 @@ -import time -import aiohttp import asyncio +import logging +import os +import statistics +import time +from typing import Dict + +import aiohttp from tabulate import tabulate -from typing import Dict, List + +from config.settings import load_config +from core.utils.asr import create_instance as create_stt_instance from core.utils.llm import create_instance as create_llm_instance from core.utils.tts import create_instance as create_tts_instance -import statistics -from config.settings import load_config -import inspect -import os -import logging # 设置全局日志级别为WARNING,抑制INFO级别日志 logging.basicConfig(level=logging.WARNING) @@ -26,7 +28,17 @@ class AsyncPerformanceTester: "请用100字概括量子计算的基本原理和应用前景", ], ) - self.results = {"llm": {}, "tts": {}, "combinations": []} + + self.test_wav_list = [] + self.wav_root = r"config/assets" + for file_name in os.listdir(self.wav_root): + file_path = os.path.join(self.wav_root, file_name) + # 检查文件大小是否大于300KB + if os.path.getsize(file_path) > 300 * 1024: # 300KB = 300 * 1024 bytes + with open(file_path, "rb") as f: + self.test_wav_list.append(f.read()) + + self.results = {"llm": {}, "tts": {}, "stt": {}, "combinations": []} async def _check_ollama_service(self, base_url: str, model_name: str) -> bool: """异步检查Ollama服务状态""" @@ -109,6 +121,57 @@ class AsyncPerformanceTester: print(f"⚠️ {tts_name} 测试失败: {str(e)}") return {"name": tts_name, "type": "tts", "errors": 1} + async def _test_stt(self, stt_name: str, config: Dict) -> Dict: + """异步测试单个STT性能""" + try: + logging.getLogger("core.providers.asr.base").setLevel(logging.WARNING) + token_fields = ["access_token", "api_key", "token"] + if any( + field in config + and any(x in config[field] for x in ["你的", "placeholder"]) + for field in token_fields + ): + print(f"⏭️ STT {stt_name} 未配置access_token/api_key,已跳过") + return {"name": stt_name, "type": "stt", "errors": 1} + + module_type = config.get("type", stt_name) + stt = create_stt_instance(module_type, config, delete_audio_file=True) + stt.audio_format = "pcm" + + print(f"🎵 测试 STT: {stt_name}") + + text, _ = await stt.speech_to_text([self.test_wav_list[0]], "1") + + if text is None: + print(f"❌ {stt_name} 连接失败") + return {"name": stt_name, "type": "stt", "errors": 1} + + total_time = 0 + test_count = len(self.test_wav_list) + + for i, sentence in enumerate(self.test_wav_list, 1): + start = time.time() + text, _ = await stt.speech_to_text([sentence], "1") + duration = time.time() - start + total_time += duration + + if text: + print(f"✓ {stt_name} [{i}/{test_count}]") + else: + print(f"✗ {stt_name} [{i}/{test_count}]") + return {"name": stt_name, "type": "stt", "errors": 1} + + return { + "name": stt_name, + "type": "stt", + "avg_time": total_time / test_count, + "errors": 0, + } + + except Exception as e: + print(f"⚠️ {stt_name} 测试失败: {str(e)}") + return {"name": stt_name, "type": "stt", "errors": 1} + async def _test_llm(self, llm_name: str, config: Dict) -> Dict: """异步测试单个LLM性能""" try: @@ -234,6 +297,7 @@ class AsyncPerformanceTester: if v["errors"] == 0 and v["avg_first_token"] >= 0.05 ] valid_tts = [k for k, v in self.results["tts"].items() if v["errors"] == 0] + valid_stt = [k for k, v in self.results["stt"].items() if v["errors"] == 0] # 找出基准值 min_first_token = ( @@ -246,42 +310,53 @@ class AsyncPerformanceTester: if valid_tts else 1 ) + min_stt_time = ( + min([self.results["stt"][stt]["avg_time"] for stt in valid_stt]) + if valid_stt + else 1 + ) for llm in valid_llms: for tts in valid_tts: - # 计算相对性能分数(越小越好) - llm_score = ( - self.results["llm"][llm]["avg_first_token"] / min_first_token - ) - tts_score = self.results["tts"][tts]["avg_time"] / min_tts_time + for stt in valid_stt: + # 计算相对性能分数(越小越好) + llm_score = ( + self.results["llm"][llm]["avg_first_token"] / min_first_token + ) + tts_score = self.results["tts"][tts]["avg_time"] / min_tts_time + stt_score = self.results["stt"][stt]["avg_time"] / min_stt_time - # 计算稳定性分数(标准差/平均值,越小越稳定) - llm_stability = ( - self.results["llm"][llm]["std_first_token"] - / self.results["llm"][llm]["avg_first_token"] - ) + # 计算稳定性分数(标准差/平均值,越小越稳定) + llm_stability = ( + self.results["llm"][llm]["std_first_token"] + / self.results["llm"][llm]["avg_first_token"] + ) - # 综合得分(考虑性能和稳定性) - # 性能权重0.7,稳定性权重0.3 - llm_final_score = llm_score * 0.7 + llm_stability * 0.3 + # 综合得分(考虑性能和稳定性) + # LLM得分: 性能权重(70%) + 稳定性权重(30%) + llm_final_score = llm_score * 0.7 + llm_stability * 0.3 - # 总分 = LLM得分(70%) + TTS得分(30%) - total_score = llm_final_score * 0.7 + tts_score * 0.3 + # 总分 = LLM得分(70%) + TTS得分(30%) + STT得分(30%) + total_score = ( + llm_final_score * 0.7 + tts_score * 0.3 + stt_score * 0.3 + ) - self.results["combinations"].append( - { - "llm": llm, - "tts": tts, - "score": total_score, - "details": { - "llm_first_token": self.results["llm"][llm][ - "avg_first_token" - ], - "llm_stability": llm_stability, - "tts_time": self.results["tts"][tts]["avg_time"], - }, - } - ) + self.results["combinations"].append( + { + "llm": llm, + "tts": tts, + "stt": stt, + "score": total_score, + "details": { + "llm_first_token": self.results["llm"][llm][ + "avg_first_token" + ], + "llm_stability": llm_stability, + "tts_time": self.results["tts"][tts]["avg_time"], + "stt_time": self.results["stt"][stt]["avg_time"], + }, + } + ) # 分数越小越好 self.results["combinations"].sort(key=lambda x: x["score"]) @@ -302,7 +377,7 @@ class AsyncPerformanceTester: ) if llm_table: - print("\nLLM 性能排行:") + print("\nLLM 性能排行:\n") print( tabulate( llm_table, @@ -321,7 +396,7 @@ class AsyncPerformanceTester: tts_table.append([name, f"{data['avg_time']:.3f}秒"]) # 不需要固定宽度 if tts_table: - print("\nTTS 性能排行:") + print("\nTTS 性能排行:\n") print( tabulate( tts_table, @@ -334,17 +409,37 @@ class AsyncPerformanceTester: else: print("\n⚠️ 没有可用的TTS模块进行测试。") + stt_table = [] + for name, data in self.results["stt"].items(): + if data["errors"] == 0: + stt_table.append([name, f"{data['avg_time']:.3f}秒"]) # 不需要固定宽度 + + if stt_table: + print("\nSTT 性能排行:\n") + print( + tabulate( + stt_table, + headers=["模型名称", "合成耗时"], + tablefmt="github", + colalign=("left", "right"), + disable_numparse=True, + ) + ) + else: + print("\n⚠️ 没有可用的STT模块进行测试。") + if self.results["combinations"]: - print("\n推荐配置组合 (得分越小越好):") + print("\n推荐配置组合 (得分越小越好):\n") combo_table = [] - for combo in self.results["combinations"][:5]: + for combo in self.results["combinations"][:]: combo_table.append( [ - f"{combo['llm']} + {combo['tts']}", # 不需要固定宽度 + f"{combo['llm']} + {combo['tts']} + {combo['stt']}", # 不需要固定宽度 f"{combo['score']:.3f}", f"{combo['details']['llm_first_token']:.3f}秒", f"{combo['details']['llm_stability']:.3f}", f"{combo['details']['tts_time']:.3f}秒", + f"{combo['details']['stt_time']:.3f}秒", ] ) @@ -357,9 +452,10 @@ class AsyncPerformanceTester: "LLM首字耗时", "稳定性", "TTS合成耗时", + "STT合成耗时", ], tablefmt="github", - colalign=("left", "right", "right", "right", "right"), + colalign=("left", "right", "right", "right", "right", "right"), disable_numparse=True, ) ) @@ -372,8 +468,12 @@ class AsyncPerformanceTester: if result["errors"] == 0: if result["type"] == "llm": self.results["llm"][result["name"]] = result - else: + elif result["type"] == "tts": self.results["tts"][result["name"]] = result + elif result["type"] == "stt": + self.results["stt"][result["name"]] = result + else: + pass async def run(self): """执行全量异步测试""" @@ -383,52 +483,73 @@ class AsyncPerformanceTester: all_tasks = [] # LLM测试任务 - for llm_name, config in self.config.get("LLM", {}).items(): - # 检查配置有效性 - if llm_name == "CozeLLM": - if any(x in config.get("bot_id", "") for x in ["你的"]) or any( - x in config.get("user_id", "") for x in ["你的"] + if self.config.get("LLM") is not None: + for llm_name, config in self.config.get("LLM", {}).items(): + # 检查配置有效性 + if llm_name == "CozeLLM": + if any(x in config.get("bot_id", "") for x in ["你的"]) or any( + x in config.get("user_id", "") for x in ["你的"] + ): + print(f"⏭️ LLM {llm_name} 未配置bot_id/user_id,已跳过") + continue + elif "api_key" in config and any( + x in config["api_key"] for x in ["你的", "placeholder", "sk-xxx"] ): - print(f"⏭️ LLM {llm_name} 未配置bot_id/user_id,已跳过") - continue - elif "api_key" in config and any( - x in config["api_key"] for x in ["你的", "placeholder", "sk-xxx"] - ): - print(f"⏭️ LLM {llm_name} 未配置api_key,已跳过") - continue - - # 对于Ollama,先检查服务状态 - if llm_name == "Ollama": - base_url = config.get("base_url", "http://localhost:11434") - model_name = config.get("model_name") - if not model_name: - print(f"🚫 Ollama未配置model_name") + print(f"⏭️ LLM {llm_name} 未配置api_key,已跳过") continue - if not await self._check_ollama_service(base_url, model_name): - continue + # 对于Ollama,先检查服务状态 + if llm_name == "Ollama": + base_url = config.get("base_url", "http://localhost:11434") + model_name = config.get("model_name") + if not model_name: + print(f"🚫 Ollama未配置model_name") + continue - print(f"📋 添加LLM测试任务: {llm_name}") - module_type = config.get("type", llm_name) - llm = create_llm_instance(module_type, config) + if not await self._check_ollama_service(base_url, model_name): + continue - # 为每个句子创建独立任务 - for sentence in self.test_sentences: - sentence = sentence.encode("utf-8").decode("utf-8") - all_tasks.append(self._test_single_sentence(llm_name, llm, sentence)) + print(f"📋 添加LLM测试任务: {llm_name}") + module_type = config.get("type", llm_name) + llm = create_llm_instance(module_type, config) + + # 为每个句子创建独立任务 + for sentence in self.test_sentences: + sentence = sentence.encode("utf-8").decode("utf-8") + all_tasks.append( + self._test_single_sentence(llm_name, llm, sentence) + ) # TTS测试任务 - for tts_name, config in self.config.get("TTS", {}).items(): - token_fields = ["access_token", "api_key", "token"] - if any( - field in config - and any(x in config[field] for x in ["你的", "placeholder"]) - for field in token_fields - ): - print(f"⏭️ TTS {tts_name} 未配置access_token/api_key,已跳过") - continue - print(f"🎵 添加TTS测试任务: {tts_name}") - all_tasks.append(self._test_tts(tts_name, config)) + if self.config.get("TTS") is not None: + for tts_name, config in self.config.get("TTS", {}).items(): + token_fields = ["access_token", "api_key", "token"] + if any( + field in config + and any(x in config[field] for x in ["你的", "placeholder"]) + for field in token_fields + ): + print(f"⏭️ TTS {tts_name} 未配置access_token/api_key,已跳过") + continue + print(f"🎵 添加TTS测试任务: {tts_name}") + all_tasks.append(self._test_tts(tts_name, config)) + + # STT测试任务 + if len(self.test_wav_list) >= 1: + if self.config.get("ASR") is not None: + for stt_name, config in self.config.get("ASR", {}).items(): + token_fields = ["access_token", "api_key", "token"] + if any( + field in config + and any(x in config[field] for x in ["你的", "placeholder"]) + for field in token_fields + ): + print(f"⏭️ ASR {stt_name} 未配置access_token/api_key,已跳过") + continue + print(f"🎵 添加ASR测试任务: {stt_name}") + all_tasks.append(self._test_stt(stt_name, config)) + else: + print(f"\n⚠️ {self.wav_root} 路径下没有音频文件,已跳过STT测试任务") print( f"\n✅ 找到 {len([t for t in all_tasks if 'test_single_sentence' in str(t)]) / len(self.test_sentences):.0f} 个可用LLM模块" @@ -436,6 +557,9 @@ class AsyncPerformanceTester: print( f"✅ 找到 {len([t for t in all_tasks if '_test_tts' in str(t)])} 个可用TTS模块" ) + print( + f"✅ 找到 {len([t for t in all_tasks if '_test_stt' in str(t)])} 个可用STT模块" + ) print("\n⏳ 开始并发测试所有模块...\n") # 并发执行所有测试任务 @@ -494,6 +618,15 @@ class AsyncPerformanceTester: if result["errors"] == 0: self.results["tts"][result["name"]] = result + # 处理STT结果 + for result in [ + r + for r in all_results + if r and isinstance(r, dict) and r.get("type") == "stt" + ]: + if result["errors"] == 0: + self.results["stt"][result["name"]] = result + # 生成组合建议并打印结果 print("\n📊 生成测试报告...") self._generate_combinations()