From d9ce5e4ce7f30f8b59447676a5063891d4d4f557 Mon Sep 17 00:00:00 2001 From: funshine Date: Tue, 15 Apr 2025 10:55:00 +0800 Subject: [PATCH 1/5] fix audio test page websocket disconn --- .../test/abbreviated_version/app.js | 10 +++- main/xiaozhi-server/test/test_page.html | 56 ++++++++++++------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/main/xiaozhi-server/test/abbreviated_version/app.js b/main/xiaozhi-server/test/abbreviated_version/app.js index 59b75625..b2286524 100644 --- a/main/xiaozhi-server/test/abbreviated_version/app.js +++ b/main/xiaozhi-server/test/abbreviated_version/app.js @@ -992,7 +992,9 @@ function connectToServer() { if(connectButton.id === "connectButton") { connectButton.textContent = '断开'; - connectButton.onclick = disconnectFromServer; + // connectButton.onclick = disconnectFromServer; + connectButton.removeEventListener("click", connectToServer); + connectButton.addEventListener("click", disconnectFromServer); } if(messageInput.id === "messageInput") { @@ -1011,7 +1013,9 @@ function connectToServer() { if(connectButton.id === "connectButton") { connectButton.textContent = '连接'; - connectButton.onclick = connectToServer; + // connectButton.onclick = connectToServer; + connectButton.removeEventListener("click", disconnectFromServer); + connectButton.addEventListener("click", connectToServer); } if(messageInput.id === "messageInput") { @@ -1175,7 +1179,7 @@ function updateStatus(message, type = 'info') { // 处理文本消息 function handleTextMessage(message) { if (message.type === 'hello') { - console.log(`服务器回应:${message.message}`); + console.log(`服务器回应:${JSON.stringify(message, null, 2)}`); } else if (message.type === 'tts') { // TTS状态消息 if (message.state === 'start') { diff --git a/main/xiaozhi-server/test/test_page.html b/main/xiaozhi-server/test/test_page.html index 2735fb5a..35dd57ef 100644 --- a/main/xiaozhi-server/test/test_page.html +++ b/main/xiaozhi-server/test/test_page.html @@ -475,22 +475,36 @@ // 日志函数 function log(message, type = 'info') { - const logEntry = document.createElement('div'); - logEntry.className = `log-entry log-${type}`; - logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; - if (type === 'error') { - logEntry.style.color = 'red'; - } else if (type === 'debug') { - logEntry.style.color = 'gray'; - return; - } else if (type === 'warning') { - logEntry.style.color = 'orange'; - } else if (type === 'success') { - logEntry.style.color = 'green'; - } else { - logEntry.style.color = 'black'; - } - logContainer.appendChild(logEntry); + // 将消息按换行符分割成多行 + const lines = message.split('\n'); + const now = new Date(); + // const timestamp = `[${now.toLocaleTimeString()}] `; + const timestamp = `[${now.toLocaleTimeString()}.${now.getMilliseconds().toString().padStart(3, '0')}] `; + // 为每一行创建日志条目 + lines.forEach((line, index) => { + const logEntry = document.createElement('div'); + logEntry.className = `log-entry log-${type}`; + // 如果是第一条日志,显示时间戳 + const prefix = index === 0 ? timestamp : ' '.repeat(timestamp.length); + logEntry.textContent = `${prefix}${line}`; + // logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; + // logEntry.style 保留起始的空格 + logEntry.style.whiteSpace = 'pre'; + if (type === 'error') { + logEntry.style.color = 'red'; + } else if (type === 'debug') { + logEntry.style.color = 'gray'; + return; + } else if (type === 'warning') { + logEntry.style.color = 'orange'; + } else if (type === 'success') { + logEntry.style.color = 'green'; + } else { + logEntry.style.color = 'black'; + } + logContainer.appendChild(logEntry); + }); + logContainer.scrollTop = logContainer.scrollHeight; } @@ -1153,7 +1167,9 @@ await sendHelloMessage(); connectButton.textContent = '断开'; - connectButton.onclick = disconnectFromServer; + connectButton.removeEventListener('click', connectToServer); + connectButton.addEventListener('click', disconnectFromServer); + // connectButton.onclick = disconnectFromServer; messageInput.disabled = false; sendTextButton.disabled = false; @@ -1169,7 +1185,9 @@ connectionStatus.style.color = 'red'; connectButton.textContent = '连接'; - connectButton.onclick = connectToServer; + connectButton.removeEventListener('click', disconnectFromServer); + connectButton.addEventListener('click', connectToServer); + // connectButton.onclick = connectToServer; messageInput.disabled = true; sendTextButton.disabled = true; recordButton.disabled = true; @@ -1189,7 +1207,7 @@ const message = JSON.parse(event.data); if (message.type === 'hello') { - log(`服务器回应:${message.message}`, 'info'); + log(`服务器回应:${JSON.stringify(message, null, 2)}`, 'success'); } else if (message.type === 'tts') { // TTS状态消息 if (message.state === 'start') { From 466a0245a9109677566bd76091c8b5e47b196f93 Mon Sep 17 00:00:00 2001 From: funshine Date: Tue, 15 Apr 2025 15:28:02 +0800 Subject: [PATCH 2/5] add default value for siliconflow tts speed --- main/xiaozhi-server/core/providers/tts/siliconflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/xiaozhi-server/core/providers/tts/siliconflow.py b/main/xiaozhi-server/core/providers/tts/siliconflow.py index be6b9e2a..b2f564cc 100644 --- a/main/xiaozhi-server/core/providers/tts/siliconflow.py +++ b/main/xiaozhi-server/core/providers/tts/siliconflow.py @@ -16,7 +16,7 @@ class TTSProvider(TTSProviderBase): self.voice = config.get("voice") self.response_format = config.get("response_format") self.sample_rate = config.get("sample_rate") - self.speed = float(config.get("speed")) + self.speed = float(config.get("speed", 1.0)) self.gain = config.get("gain") self.host = "api.siliconflow.cn" From ee83cea11c082232d7edaacde9176062f02b1f44 Mon Sep 17 00:00:00 2001 From: funshine Date: Tue, 15 Apr 2025 15:51:36 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E6=AD=A3CosyVoiceSiliconflow?= =?UTF-8?q?=E9=9F=B3=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/db/changelog/202504151547.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 main/manager-api/src/main/resources/db/changelog/202504151547.sql diff --git a/main/manager-api/src/main/resources/db/changelog/202504151547.sql b/main/manager-api/src/main/resources/db/changelog/202504151547.sql new file mode 100644 index 00000000..e48a077c --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202504151547.sql @@ -0,0 +1,4 @@ +-- 修正CosyVoiceSiliconflow音色 +delete from `ai_tts_voice` where tts_model_id = 'TTS_CosyVoiceSiliconflow'; +INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0001', 'TTS_CosyVoiceSiliconflow', 'CosyVoice男声', 'FunAudioLLM/CosyVoice2-0.5B:alex', '中文', 'https://example.com/cosyvoice/alex.mp3', NULL, 6, NULL, NULL, NULL, NULL); +INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0002', 'TTS_CosyVoiceSiliconflow', 'CosyVoice女声', 'FunAudioLLM/CosyVoice2-0.5B:bella', '中文', 'https://example.com/cosyvoice/bella.mp3', NULL, 6, NULL, NULL, NULL, NULL); \ No newline at end of file From 4e0a3941ffd407351da72a42f5d724f50f02dbf5 Mon Sep 17 00:00:00 2001 From: haotian Date: Tue, 15 Apr 2025 17:18:59 +0800 Subject: [PATCH 4/5] =?UTF-8?q?update:=20=E5=A2=9E=E5=8A=A0prompt=E4=B8=AA?= =?UTF-8?q?=E6=80=A7=E5=8C=96=E9=85=8D=E7=BD=AE=20&=20=E5=A2=9E=E5=8A=A0va?= =?UTF-8?q?d,asr=E4=B8=AA=E6=80=A7=E5=88=9D=E5=A7=8B=E5=8C=96=20&=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97=E8=8B=A5=E5=B9=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/connection.py | 6 +++ main/xiaozhi-server/core/utils/util.py | 73 +++++++++++++++----------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 146241ff..3f582fa7 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -270,6 +270,10 @@ class ConnectionHandler: except Exception as e: self.logger.bind(tag=TAG).error(f"初始化组件失败: {e}") modules = {} + if modules.get("vad", None) is not None: + self.vad = modules["vad"] + if modules.get("asr", None) is not None: + self.asr = modules["asr"] if modules.get("tts", None) is not None: self.tts = modules["tts"] if modules.get("llm", None) is not None: @@ -278,6 +282,8 @@ class ConnectionHandler: self.intent = modules["intent"] if modules.get("memory", None) is not None: self.memory = modules["memory"] + if modules.get("prompt", None) is not None: + self.change_system_prompt(modules["prompt"]) def _initialize_memory(self): """初始化记忆模块""" diff --git a/main/xiaozhi-server/core/utils/util.py b/main/xiaozhi-server/core/utils/util.py index dd56f5ae..7f998c5a 100644 --- a/main/xiaozhi-server/core/utils/util.py +++ b/main/xiaozhi-server/core/utils/util.py @@ -222,80 +222,93 @@ def initialize_modules( # 初始化TTS模块 if init_tts: + select_tts_module = config["selected_module"]["TTS"] tts_type = ( - config["selected_module"]["TTS"] - if "type" not in config["TTS"][config["selected_module"]["TTS"]] - else config["TTS"][config["selected_module"]["TTS"]]["type"] + select_tts_module + if "type" not in config["TTS"][select_tts_module] + else config["TTS"][select_tts_module]["type"] ) modules["tts"] = tts.create_instance( tts_type, - config["TTS"][config["selected_module"]["TTS"]], + config["TTS"][select_tts_module], bool(config.get("delete_audio", True)), ) - logger.bind(tag=TAG).info(f"初始化组件: tts成功") + logger.bind(tag=TAG).info(f"初始化组件: tts成功 {select_tts_module}") # 初始化LLM模块 if init_llm: + select_llm_module = config["selected_module"]["TTS"] llm_type = ( - config["selected_module"]["LLM"] - if "type" not in config["LLM"][config["selected_module"]["LLM"]] - else config["LLM"][config["selected_module"]["LLM"]]["type"] + select_llm_module + if "type" not in config["LLM"][select_llm_module] + else config["LLM"][select_llm_module]["type"] ) modules["llm"] = llm.create_instance( llm_type, - config["LLM"][config["selected_module"]["LLM"]], + config["LLM"][select_llm_module], ) - logger.bind(tag=TAG).info(f"初始化组件: llm成功") + logger.bind(tag=TAG).info(f"初始化组件: llm成功 {select_llm_module}") # 初始化Intent模块 if init_intent: + select_intent_module = config["selected_module"]["Intent"] intent_type = ( - config["selected_module"]["Intent"] - if "type" not in config["Intent"][config["selected_module"]["Intent"]] - else config["Intent"][config["selected_module"]["Intent"]]["type"] + select_intent_module + if "type" not in config["Intent"][select_intent_module] + else config["Intent"][select_intent_module]["type"] ) modules["intent"] = intent.create_instance( intent_type, - config["Intent"][config["selected_module"]["Intent"]], + config["Intent"][select_intent_module], ) - logger.bind(tag=TAG).info(f"初始化组件: intent成功") + logger.bind(tag=TAG).info(f"初始化组件: intent成功 {select_intent_module}") + # 初始化Memory模块 if init_memory: + select_memory_module = config["selected_module"]["Memory"] memory_type = ( - config["selected_module"]["Memory"] - if "type" not in config["Memory"][config["selected_module"]["Memory"]] - else config["Memory"][config["selected_module"]["Memory"]]["type"] + select_memory_module + if "type" not in config["Memory"][select_memory_module] + else config["Memory"][select_memory_module]["type"] ) modules["memory"] = memory.create_instance( memory_type, - config["Memory"][config["selected_module"]["Memory"]], + config["Memory"][select_memory_module], ) - logger.bind(tag=TAG).info(f"初始化组件: memory成功") + logger.bind(tag=TAG).info(f"初始化组件: memory成功 {select_memory_module}") # 初始化VAD模块 if init_vad: + select_vad_module = config["selected_module"]["VAD"] vad_type = ( - config["selected_module"]["VAD"] - if "type" not in config["VAD"][config["selected_module"]["VAD"]] - else config["VAD"][config["selected_module"]["VAD"]]["type"] + select_vad_module + if "type" not in config["VAD"][select_vad_module] + else config["VAD"][select_vad_module]["type"] ) modules["vad"] = vad.create_instance( vad_type, - config["VAD"][config["selected_module"]["VAD"]], + config["VAD"][select_vad_module], ) - logger.bind(tag=TAG).info(f"初始化组件: vad成功") + logger.bind(tag=TAG).info(f"初始化组件: vad成功 {select_vad_module}") + # 初始化ASR模块 if init_asr: + select_asr_module = config["selected_module"]["ASR"] asr_type = ( - config["selected_module"]["ASR"] - if "type" not in config["ASR"][config["selected_module"]["ASR"]] - else config["ASR"][config["selected_module"]["ASR"]]["type"] + select_asr_module + if "type" not in config["ASR"][select_asr_module] + else config["ASR"][select_asr_module]["type"] ) modules["asr"] = asr.create_instance( asr_type, - config["ASR"][config["selected_module"]["ASR"]], + config["ASR"][select_asr_module], bool(config.get("delete_audio", True)), ) - logger.bind(tag=TAG).info(f"初始化组件: asr成功") + logger.bind(tag=TAG).info(f"初始化组件: asr成功 {select_asr_module}") + + # 初始化自定义prompt + if config["prompt"]: + modules["prompt"] = config["prompt"] + logger.bind(tag=TAG).info(f"初始化组件: prompt成功 {modules['prompt'][:30]}") return modules From 1354cf2a876919da61f0cf159d7f3638f6a2f6ab Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Tue, 15 Apr 2025 22:46:54 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=90=88=E5=B9=B6=E7=BD=91=E5=8F=8B?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/security/controller/LoginController.java | 2 +- .../db/changelog/{202504151205.sql => 202504151206.sql} | 5 +++++ .../src/main/resources/db/changelog/202504151547.sql | 4 ---- .../main/resources/db/changelog/db.changelog-master.yaml | 4 ++-- main/xiaozhi-server/config/logger.py | 2 +- main/xiaozhi-server/core/connection.py | 2 -- main/xiaozhi-server/core/utils/util.py | 6 +++--- 7 files changed, 12 insertions(+), 13 deletions(-) rename main/manager-api/src/main/resources/db/changelog/{202504151205.sql => 202504151206.sql} (80%) delete mode 100644 main/manager-api/src/main/resources/db/changelog/202504151547.sql 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 f83e49db..b4bacd42 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 @@ -121,7 +121,7 @@ public class LoginController { @Operation(summary = "公共配置") public Result> pubConfig() { Map config = new HashMap<>(); - config.put("version", "0.3.3"); + config.put("version", "0.3.4"); config.put("allowUserRegister", sysUserService.getAllowUserRegister()); return new Result>().ok(config); } diff --git a/main/manager-api/src/main/resources/db/changelog/202504151205.sql b/main/manager-api/src/main/resources/db/changelog/202504151206.sql similarity index 80% rename from main/manager-api/src/main/resources/db/changelog/202504151205.sql rename to main/manager-api/src/main/resources/db/changelog/202504151206.sql index 0b72121e..cb51cef9 100644 --- a/main/manager-api/src/main/resources/db/changelog/202504151205.sql +++ b/main/manager-api/src/main/resources/db/changelog/202504151206.sql @@ -21,3 +21,8 @@ INSERT INTO `ai_tts_voice` VALUES delete from `sys_params` where id in (103,104); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (103, 'server.allow_user_register', 'false', 'boolean', 1, '是否运行管理员以外的人注册'); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (104, 'server.fronted_url', 'http://xiaozhi.server.com', 'string', 1, '下发六位验证码时显示的控制面板地址'); + +-- 修正CosyVoiceSiliconflow音色 +delete from `ai_tts_voice` where tts_model_id = 'TTS_CosyVoiceSiliconflow'; +INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0001', 'TTS_CosyVoiceSiliconflow', 'CosyVoice男声', 'FunAudioLLM/CosyVoice2-0.5B:alex', '中文', 'https://example.com/cosyvoice/alex.mp3', NULL, 6, NULL, NULL, NULL, NULL); +INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0002', 'TTS_CosyVoiceSiliconflow', 'CosyVoice女声', 'FunAudioLLM/CosyVoice2-0.5B:bella', '中文', 'https://example.com/cosyvoice/bella.mp3', NULL, 6, NULL, NULL, NULL, NULL); diff --git a/main/manager-api/src/main/resources/db/changelog/202504151547.sql b/main/manager-api/src/main/resources/db/changelog/202504151547.sql deleted file mode 100644 index e48a077c..00000000 --- a/main/manager-api/src/main/resources/db/changelog/202504151547.sql +++ /dev/null @@ -1,4 +0,0 @@ --- 修正CosyVoiceSiliconflow音色 -delete from `ai_tts_voice` where tts_model_id = 'TTS_CosyVoiceSiliconflow'; -INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0001', 'TTS_CosyVoiceSiliconflow', 'CosyVoice男声', 'FunAudioLLM/CosyVoice2-0.5B:alex', '中文', 'https://example.com/cosyvoice/alex.mp3', NULL, 6, NULL, NULL, NULL, NULL); -INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0002', 'TTS_CosyVoiceSiliconflow', 'CosyVoice女声', 'FunAudioLLM/CosyVoice2-0.5B:bella', '中文', 'https://example.com/cosyvoice/bella.mp3', NULL, 6, NULL, NULL, NULL, NULL); \ 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 7060e32c..178f9ebe 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 @@ -52,9 +52,9 @@ databaseChangeLog: encoding: utf8 path: classpath:db/changelog/202504112058.sql - changeSet: - id: 202504151205 + id: 202504151206 author: John changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202504151205.sql + path: classpath:db/changelog/202504151206.sql diff --git a/main/xiaozhi-server/config/logger.py b/main/xiaozhi-server/config/logger.py index 96d1fe65..025be960 100644 --- a/main/xiaozhi-server/config/logger.py +++ b/main/xiaozhi-server/config/logger.py @@ -3,7 +3,7 @@ import sys from loguru import logger from config.config_loader import load_config -SERVER_VERSION = "0.3.3" +SERVER_VERSION = "0.3.4" def get_module_abbreviation(module_name, module_dict): diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 33d93347..283fe3f6 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -269,8 +269,6 @@ class ConnectionHandler: self.config["selected_module"]["Intent"] = private_config[ "selected_module" ]["Intent"] - if private_config.get("prompt", None) is not None: - self.config["prompt"] = private_config["prompt"] try: modules = initialize_modules( self.logger, diff --git a/main/xiaozhi-server/core/utils/util.py b/main/xiaozhi-server/core/utils/util.py index 7f998c5a..238bf5cb 100644 --- a/main/xiaozhi-server/core/utils/util.py +++ b/main/xiaozhi-server/core/utils/util.py @@ -237,7 +237,7 @@ def initialize_modules( # 初始化LLM模块 if init_llm: - select_llm_module = config["selected_module"]["TTS"] + select_llm_module = config["selected_module"]["LLM"] llm_type = ( select_llm_module if "type" not in config["LLM"][select_llm_module] @@ -307,8 +307,8 @@ def initialize_modules( logger.bind(tag=TAG).info(f"初始化组件: asr成功 {select_asr_module}") # 初始化自定义prompt - if config["prompt"]: + if config.get("prompt", None) is not None: modules["prompt"] = config["prompt"] - logger.bind(tag=TAG).info(f"初始化组件: prompt成功 {modules['prompt'][:30]}") + logger.bind(tag=TAG).info(f"初始化组件: prompt成功 {modules['prompt'][:50]}...") return modules