From cc7ba0872c9961a3151a3b175371bca07d01cea6 Mon Sep 17 00:00:00 2001 From: 3030332422 <3030332422@qq.com> Date: Wed, 27 Aug 2025 14:39:05 +0800 Subject: [PATCH 01/13] =?UTF-8?q?update:=E6=B7=BB=E5=8A=A0vosk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/db/changelog/202508271113.sql | 24 ++++ .../db/changelog/db.changelog-master.yaml | 7 ++ main/xiaozhi-server/config.yaml | 7 ++ .../xiaozhi-server/core/providers/asr/vosk.py | 114 ++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 main/manager-api/src/main/resources/db/changelog/202508271113.sql create mode 100644 main/xiaozhi-server/core/providers/asr/vosk.py diff --git a/main/manager-api/src/main/resources/db/changelog/202508271113.sql b/main/manager-api/src/main/resources/db/changelog/202508271113.sql new file mode 100644 index 00000000..1393932c --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202508271113.sql @@ -0,0 +1,24 @@ +-- VOSK ASR模型供应器 +delete from `ai_model_provider` where id = 'SYSTEM_ASR_VoskASR'; +INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES +('SYSTEM_ASR_VoskASR', 'ASR', 'vosk', 'VOSK离线语音识别', '[{"key": "model_path", "type": "string", "label": "模型路径"}, {"key": "output_dir", "type": "string", "label": "输出目录"}]', 11, 1, NOW(), 1, NOW()); + +-- VOSK ASR模型配置 +delete from `ai_model_config` where id = 'ASR_VoskASR'; +INSERT INTO `ai_model_config` VALUES ('ASR_VoskASR', 'ASR', 'VoskASR', 'VOSK离线语音识别', 0, 1, '{\"type\": \"vosk\", \"model_path\": \"models/vosk/vosk-model-small-cn-0.22\", \"output_dir\": \"tmp/\"}', NULL, NULL, 11, NULL, NULL, NULL, NULL); + +-- 更新VOSK ASR配置说明 +UPDATE `ai_model_config` SET +`doc_link` = 'https://alphacephei.com/vosk/', +`remark` = 'VOSK ASR配置说明: +1. VOSK是一个离线语音识别库,支持多种语言 +2. 需要先下载模型文件:https://alphacephei.com/vosk/models +3. 中文模型推荐使用vosk-model-small-cn-0.22或vosk-model-cn-0.22 +4. 完全离线运行,无需网络连接 +5. 输出文件保存在tmp/目录 +使用步骤: +1. 访问 https://alphacephei.com/vosk/models 下载中文模型 +2. 解压模型文件到项目目录下的models/vosk/文件夹 +3. 在配置中指定正确的模型路径 +4. 注意:VOSK中文模型输出不带标点符号,词与词之间会有空格 +' WHERE `id` = 'ASR_VoskASR'; \ 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 0e8d3dc3..74862bc1 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 @@ -303,3 +303,10 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202508131557.sql + - changeSet: + id: 202508271113 + author: cgd + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202508271113.sql diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index 51b6a617..d9d7fa88 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -383,6 +383,13 @@ ASR: base_url: https://api.groq.com/openai/v1/audio/transcriptions model_name: whisper-large-v3-turbo output_dir: tmp/ + VoskASR: + # 官方网站:https://alphacephei.com/vosk/ + # 模型下载地址:https://alphacephei.com/vosk/models + # 解压后放到models/vosk目录下 + type: vosk + model_path: 你的模型路径,如:models/vosk/vosk-model-small-cn-0.22 + output_dir: tmp/ diff --git a/main/xiaozhi-server/core/providers/asr/vosk.py b/main/xiaozhi-server/core/providers/asr/vosk.py new file mode 100644 index 00000000..7ec091b2 --- /dev/null +++ b/main/xiaozhi-server/core/providers/asr/vosk.py @@ -0,0 +1,114 @@ +import os +import json +import time +from typing import Optional, Tuple, List +from .base import ASRProviderBase +from config.logger import setup_logging +from core.providers.asr.dto.dto import InterfaceType +import vosk + +TAG = __name__ +logger = setup_logging() + +class ASRProvider(ASRProviderBase): + def __init__(self, config: dict, delete_audio_file: bool = True): + super().__init__() + self.interface_type = InterfaceType.NON_STREAM + self.model_path = config.get("model_path", "models/vosk/vosk-model-small-cn-0.22") + self.output_dir = config.get("output_dir", "tmp/") + self.delete_audio_file = delete_audio_file + + # 初始化VOSK模型 + self.model = None + self.recognizer = None + self._load_model() + + # 确保输出目录存在 + os.makedirs(self.output_dir, exist_ok=True) + + def _load_model(self): + """加载VOSK模型""" + try: + if not os.path.exists(self.model_path): + raise FileNotFoundError(f"VOSK模型路径不存在: {self.model_path}") + + logger.bind(tag=TAG).info(f"正在加载VOSK模型: {self.model_path}") + self.model = vosk.Model(self.model_path) + + # 初始化VOSK识别器(采样率必须为16kHz) + self.recognizer = vosk.KaldiRecognizer(self.model, 16000) + + logger.bind(tag=TAG).info("VOSK模型加载成功") + except Exception as e: + logger.bind(tag=TAG).error(f"加载VOSK模型失败: {e}") + raise + + async def speech_to_text( + self, audio_data: List[bytes], session_id: str, audio_format: str = "opus" + ) -> Tuple[Optional[str], Optional[str]]: + """将语音数据转换为文本""" + file_path = None + try: + # 检查模型是否加载成功 + if not self.model: + logger.bind(tag=TAG).error("VOSK模型未加载,无法进行识别") + return "", None + + # 解码音频(如果原始格式是Opus) + if audio_format == "pcm": + pcm_data = audio_data + else: + pcm_data = self.decode_opus(audio_data) + + if not pcm_data: + logger.bind(tag=TAG).warning("解码后的PCM数据为空,无法进行识别") + return "", None + + # 合并PCM数据 + combined_pcm_data = b"".join(pcm_data) + if len(combined_pcm_data) == 0: + logger.bind(tag=TAG).warning("合并后的PCM数据为空") + return "", None + + # 判断是否保存为WAV文件 + if not self.delete_audio_file: + file_path = self.save_audio_to_file(pcm_data, session_id) + + start_time = time.time() + + + # 进行识别(VOSK推荐每次送入2000字节的数据) + chunk_size = 2000 + text_result = "" + + for i in range(0, len(combined_pcm_data), chunk_size): + chunk = combined_pcm_data[i:i+chunk_size] + if self.recognizer.AcceptWaveform(chunk): + result = json.loads(self.recognizer.Result()) + text = result.get('text', '') + if text: + text_result += text + " " + + # 获取最终结果 + final_result = json.loads(self.recognizer.FinalResult()) + final_text = final_result.get('text', '') + if final_text: + text_result += final_text + + logger.bind(tag=TAG).debug( + f"VOSK语音识别耗时: {time.time() - start_time:.3f}s | 结果: {text_result.strip()}" + ) + + return text_result.strip(), file_path + + except Exception as e: + logger.bind(tag=TAG).error(f"VOSK语音识别失败: {e}") + return "", None + finally: + # 文件清理逻辑 + if self.delete_audio_file and file_path and os.path.exists(file_path): + try: + os.remove(file_path) + logger.bind(tag=TAG).debug(f"已删除临时音频文件: {file_path}") + except Exception as e: + logger.bind(tag=TAG).error(f"文件删除失败: {file_path} | 错误: {e}") From a3827aed6e910adf32f844f3c58881a2fa2dd86e Mon Sep 17 00:00:00 2001 From: 3030332422 <3030332422@qq.com> Date: Wed, 27 Aug 2025 15:54:25 +0800 Subject: [PATCH 02/13] =?UTF-8?q?fix:=E4=BF=AE=E6=94=B9=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/config.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index d9d7fa88..1e52f748 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -385,8 +385,17 @@ ASR: output_dir: tmp/ VoskASR: # 官方网站:https://alphacephei.com/vosk/ - # 模型下载地址:https://alphacephei.com/vosk/models - # 解压后放到models/vosk目录下 + # 配置说明: + # 1. VOSK是一个离线语音识别库,支持多种语言 + # 2. 需要先下载模型文件:https://alphacephei.com/vosk/models + # 3. 中文模型推荐使用vosk-model-small-cn-0.22或vosk-model-cn-0.22 + # 4. 完全离线运行,无需网络连接 + # 5. 输出文件保存在tmp/目录 + # 使用步骤: + # 1. 访问 https://alphacephei.com/vosk/models 下载对应的模型 + # 2. 解压模型文件到项目目录下的models/vosk/文件夹 + # 3. 在配置中指定正确的模型路径 + # 4. 注意:VOSK中文模型输出不带标点符号,词与词之间会有空格 type: vosk model_path: 你的模型路径,如:models/vosk/vosk-model-small-cn-0.22 output_dir: tmp/ From c82cf670de08ad59e334e236bea319420b0e9a1a Mon Sep 17 00:00:00 2001 From: 3030332422 <3030332422@qq.com> Date: Wed, 27 Aug 2025 16:42:17 +0800 Subject: [PATCH 03/13] =?UTF-8?q?update:=E5=88=A0=E5=8E=BB=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=A8=A1=E5=9E=8B=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/db/changelog/202508271113.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/manager-api/src/main/resources/db/changelog/202508271113.sql b/main/manager-api/src/main/resources/db/changelog/202508271113.sql index 1393932c..6d020803 100644 --- a/main/manager-api/src/main/resources/db/changelog/202508271113.sql +++ b/main/manager-api/src/main/resources/db/changelog/202508271113.sql @@ -5,7 +5,7 @@ INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `f -- VOSK ASR模型配置 delete from `ai_model_config` where id = 'ASR_VoskASR'; -INSERT INTO `ai_model_config` VALUES ('ASR_VoskASR', 'ASR', 'VoskASR', 'VOSK离线语音识别', 0, 1, '{\"type\": \"vosk\", \"model_path\": \"models/vosk/vosk-model-small-cn-0.22\", \"output_dir\": \"tmp/\"}', NULL, NULL, 11, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('ASR_VoskASR', 'ASR', 'VoskASR', 'VOSK离线语音识别', 0, 1, '{\"type\": \"vosk\", \"model_path\": \"\", \"output_dir\": \"tmp/\"}', NULL, NULL, 11, NULL, NULL, NULL, NULL); -- 更新VOSK ASR配置说明 UPDATE `ai_model_config` SET From 74bc5dbb7dfc888c9341d3de4398ab2510e05d32 Mon Sep 17 00:00:00 2001 From: Chingfeng Li Date: Wed, 3 Sep 2025 15:41:35 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E4=BC=98=E5=8C=96SSE=20Client=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=EF=BC=9B=E5=A2=9E=E5=8A=A0SSE=20MCP=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/providers/tools/server_mcp/mcp_client.py | 8 +------- main/xiaozhi-server/mcp_server_settings.json | 6 ++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py b/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py index 8b60ac1b..a30af31f 100644 --- a/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py +++ b/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py @@ -167,14 +167,8 @@ class ServerMCPClient: # 建立SSEClient elif "url" in self.config: - if "API_ACCESS_TOKEN" in self.config: - headers = { - "Authorization": f"Bearer {self.config['API_ACCESS_TOKEN']}" - } - else: - headers = {} sse_r, sse_w = await stack.enter_async_context( - sse_client(self.config["url"], headers=headers) + sse_client(self.config["url"], headers=self.config.get("headers", None), timeout=self.config.get("timeout", 5), sse_read_timeout=self.config.get("sse_read_timeout", 60 * 5)) ) read_stream, write_stream = sse_r, sse_w diff --git a/main/xiaozhi-server/mcp_server_settings.json b/main/xiaozhi-server/mcp_server_settings.json index a1bddf06..70607a2c 100644 --- a/main/xiaozhi-server/mcp_server_settings.json +++ b/main/xiaozhi-server/mcp_server_settings.json @@ -36,6 +36,12 @@ "command": "npx", "args": ["-y", "@simonb97/server-win-cli"], "link": "https://github.com/SimonB97/win-cli-mcp-server" + }, + "sse-mcp-server": { + "url": "http://localhost:8080/sse", + "headers": { + "Authorization": "Bearer YOUR TOKEN" + } } } } From 74f321a0fddd7f3d816e8dfee49dd932836b6551 Mon Sep 17 00:00:00 2001 From: Chingfeng Li Date: Wed, 3 Sep 2025 17:53:02 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=92=8C=E8=BF=87=E6=9C=9F=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/providers/tools/server_mcp/mcp_client.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py b/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py index a30af31f..6dd14195 100644 --- a/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py +++ b/main/xiaozhi-server/core/providers/tools/server_mcp/mcp_client.py @@ -167,8 +167,13 @@ class ServerMCPClient: # 建立SSEClient elif "url" in self.config: + headers = dict(self.config.get("headers", {})) + # TODO 兼容旧版本 + if "API_ACCESS_TOKEN" in self.config: + headers["Authorization"] = f"Bearer {self.config['API_ACCESS_TOKEN']}" + self.logger.bind(tag=TAG).warning(f"你正在使用旧过时的配置 API_ACCESS_TOKEN ,请在.mcp_server_settings.json中将API_ACCESS_TOKEN直接设置在headers中,例如 'Authorization': 'Bearer API_ACCESS_TOKEN'") sse_r, sse_w = await stack.enter_async_context( - sse_client(self.config["url"], headers=self.config.get("headers", None), timeout=self.config.get("timeout", 5), sse_read_timeout=self.config.get("sse_read_timeout", 60 * 5)) + sse_client(self.config["url"], headers=headers, timeout=self.config.get("timeout", 5), sse_read_timeout=self.config.get("sse_read_timeout", 60 * 5)) ) read_stream, write_stream = sse_r, sse_w From 25d9e6c8cfae31d2febe94f3c43d18a7ac394bcd Mon Sep 17 00:00:00 2001 From: 3030332422 <3030332422@qq.com> Date: Sun, 7 Sep 2025 15:30:04 +0800 Subject: [PATCH 06/13] =?UTF-8?q?update:=20=E5=A3=B0=E7=BA=B9=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E6=B7=BB=E5=8A=A0=E7=9B=B8=E4=BC=BC=E5=BA=A6=E9=98=88?= =?UTF-8?q?=E5=80=BC=E6=A3=80=E6=9F=A5=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/config.yaml | 3 +++ .../xiaozhi-server/core/utils/voiceprint_provider.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index c0aa3f93..24947be4 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -148,6 +148,9 @@ voiceprint: - "test1,张三,张三是一个程序员" - "test2,李四,李四是一个产品经理" - "test3,王五,王五是一个设计师" + # 声纹识别相似度阈值,范围0.0-1.0,默认0.4 + # 数值越高越严格,减少误识别但可能增加拒识率 + similarity_threshold: 0.4 # ##################################################################################### # ################################以下是角色模型配置###################################### diff --git a/main/xiaozhi-server/core/utils/voiceprint_provider.py b/main/xiaozhi-server/core/utils/voiceprint_provider.py index 8e788172..5d95b73a 100644 --- a/main/xiaozhi-server/core/utils/voiceprint_provider.py +++ b/main/xiaozhi-server/core/utils/voiceprint_provider.py @@ -19,6 +19,8 @@ class VoiceprintProvider: self.original_url = config.get("url", "") self.speakers = config.get("speakers", []) self.speaker_map = self._parse_speakers() + # 声纹识别相似度阈值,默认0.4 + self.similarity_threshold = float(config.get("similarity_threshold", 0.4)) # 解析API地址和密钥 self.api_url = None @@ -62,7 +64,7 @@ class VoiceprintProvider: # 进行健康检查,验证服务器是否可用 if self._check_server_health(): self.enabled = True - logger.bind(tag=TAG).info(f"声纹识别已启用: API={self.api_url}, 说话人={len(self.speaker_ids)}个") + logger.bind(tag=TAG).info(f"声纹识别已启用: API={self.api_url}, 说话人={len(self.speaker_ids)}个, 相似度阈值={self.similarity_threshold}") else: self.enabled = False logger.bind(tag=TAG).warning(f"声纹识别服务器不可用,声纹识别已禁用: {self.api_url}") @@ -169,12 +171,14 @@ class VoiceprintProvider: logger.bind(tag=TAG).info(f"声纹识别耗时: {total_elapsed_time:.3f}s") - # 置信度检查 - if score < 0.5: - logger.bind(tag=TAG).warning(f"声纹识别置信度较低: {score:.3f}") + # 相似度阈值检查 + if score < self.similarity_threshold: + logger.bind(tag=TAG).warning(f"声纹识别相似度{score:.3f}低于阈值{self.similarity_threshold},拒绝识别") + return "未知说话人" if speaker_id and speaker_id in self.speaker_map: result_name = self.speaker_map[speaker_id]["name"] + logger.bind(tag=TAG).info(f"声纹识别成功: {result_name} (相似度: {score:.3f})") return result_name else: logger.bind(tag=TAG).warning(f"未识别的说话人ID: {speaker_id}") From d66db60177c0b68c22163e79843e58b02e7e197d Mon Sep 17 00:00:00 2001 From: 3030332422 <3030332422@qq.com> Date: Mon, 8 Sep 2025 09:32:10 +0800 Subject: [PATCH 07/13] =?UTF-8?q?update:=E4=BF=AE=E6=94=B9=E5=A3=B0?= =?UTF-8?q?=E7=BA=B9=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/utils/voiceprint_provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/xiaozhi-server/core/utils/voiceprint_provider.py b/main/xiaozhi-server/core/utils/voiceprint_provider.py index 5d95b73a..ee4f06ca 100644 --- a/main/xiaozhi-server/core/utils/voiceprint_provider.py +++ b/main/xiaozhi-server/core/utils/voiceprint_provider.py @@ -173,7 +173,7 @@ class VoiceprintProvider: # 相似度阈值检查 if score < self.similarity_threshold: - logger.bind(tag=TAG).warning(f"声纹识别相似度{score:.3f}低于阈值{self.similarity_threshold},拒绝识别") + logger.bind(tag=TAG).warning(f"声纹识别相似度{score:.3f}低于阈值{self.similarity_threshold}") return "未知说话人" if speaker_id and speaker_id in self.speaker_map: From 0d19c693a98936e03cc3831f882313b4bb5b327e Mon Sep 17 00:00:00 2001 From: Chingfeng Li Date: Mon, 8 Sep 2025 14:24:50 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=A9=E6=B0=94?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/config.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index c0aa3f93..3cbc036e 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -114,7 +114,10 @@ plugins: # 想稳定一点就自行申请替换,每天有1000次免费调用 # 申请地址:https://console.qweather.com/#/apps/create-key/over # 申请后通过这个链接可以找到自己的apihost:https://console.qweather.com/setting?lang=zh - get_weather: {"api_host":"mj7p3y7naa.re.qweatherapi.com", "api_key": "a861d0d5e7bf4ee1a83d9a9e4f96d4da", "default_location": "广州" } + get_weather: + api_host: "mj7p3y7naa.re.qweatherapi.com" + api_key: "a861d0d5e7bf4ee1a83d9a9e4f96d4da" + default_location: "广州" # 获取新闻插件的配置,这里根据需要的新闻类型传入对应的url链接,默认支持社会、科技、财经新闻 # 更多类型的新闻列表查看 https://www.chinanews.com.cn/rss/ get_news_from_chinanews: From 8aed23f21a5da0ac19927fc0edfeb6a86314dbbb Mon Sep 17 00:00:00 2001 From: 3030332422 <3030332422@qq.com> Date: Mon, 8 Sep 2025 16:25:08 +0800 Subject: [PATCH 09/13] =?UTF-8?q?update:=E6=99=BA=E6=8E=A7=E5=8F=B0?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9B=B8=E4=BC=BC=E5=BA=A6=E9=98=88=E5=80=BC?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/service/impl/ConfigServiceImpl.java | 14 ++++++++++++++ .../main/resources/db/changelog/202509081140.sql | 4 ++++ .../db/changelog/db.changelog-master.yaml | 7 +++++++ 3 files changed, 25 insertions(+) create mode 100644 main/manager-api/src/main/resources/db/changelog/202509081140.sql diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java index 476f09cd..5586b9f0 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java @@ -298,6 +298,20 @@ public class ConfigServiceImpl implements ConfigService { Map voiceprintConfig = new HashMap<>(); voiceprintConfig.put("url", voiceprintUrl); voiceprintConfig.put("speakers", speakers); + + // 获取声纹识别相似度阈值,默认0.4 + String thresholdStr = sysParamsService.getValue("server.voiceprint_similarity_threshold", true); + if (StringUtils.isNotBlank(thresholdStr) && !"null".equals(thresholdStr)) { + try { + double threshold = Double.parseDouble(thresholdStr); + voiceprintConfig.put("similarity_threshold", threshold); + } catch (NumberFormatException e) { + // 如果解析失败,使用默认值0.4 + voiceprintConfig.put("similarity_threshold", 0.4); + } + } else { + voiceprintConfig.put("similarity_threshold", 0.4); + } result.put("voiceprint", voiceprintConfig); } catch (Exception e) { diff --git a/main/manager-api/src/main/resources/db/changelog/202509081140.sql b/main/manager-api/src/main/resources/db/changelog/202509081140.sql new file mode 100644 index 00000000..9dec9d04 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202509081140.sql @@ -0,0 +1,4 @@ +-- 添加声纹识别相似度阈值参数配置 +delete from `sys_params` where id = 115; +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) +VALUES (115, 'server.voiceprint_similarity_threshold', '0.4', 'string', 1, '声纹识别相似度阈值,范围0.0-1.0,默认0.4,数值越高越严格'); 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 0e8d3dc3..dada3c78 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 @@ -303,3 +303,10 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202508131557.sql + - changeSet: + id: 202509081140 + author: cgd + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202509081140.sql From 23dc6f1ea90e5b638e8ca9ea4c0c4d7f30d724f1 Mon Sep 17 00:00:00 2001 From: Chingfeng Li Date: Mon, 8 Sep 2025 16:26:39 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E5=A3=B0=E7=BA=B9=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/config.yaml | 1 + main/xiaozhi-server/core/connection.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index c0aa3f93..72365f62 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -141,6 +141,7 @@ plugins: # 声纹识别配置 voiceprint: + enable: false # 声纹接口地址 url: # 说话人配置:speaker_id,名称,描述 diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 4b3b9d1c..6bbfbda9 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -430,12 +430,16 @@ class ConnectionHandler: def _initialize_voiceprint(self): """为当前连接初始化声纹识别""" try: - voiceprint_config = self.config.get("voiceprint", {}) - if voiceprint_config: - self.voiceprint_provider = VoiceprintProvider(voiceprint_config) - self.logger.bind(tag=TAG).info("声纹识别功能已在连接时动态启用") + voiceprint_enable = self.config.get("voiceprint", {}).get("enable", False) + if voiceprint_enable: + voiceprint_provider = VoiceprintProvider(self.config.get("voiceprint", {})) + if voiceprint_provider is not None and voiceprint_provider.enabled: + self.voiceprint_provider = voiceprint_provider + self.logger.bind(tag=TAG).info("声纹识别功能已在连接时动态启用") + else: + self.logger.bind(tag=TAG).warning("声纹识别功能启用但配置不完整") else: - self.logger.bind(tag=TAG).info("声纹识别功能未启用或配置不完整") + self.logger.bind(tag=TAG).info("声纹识别功能未启用") except Exception as e: self.logger.bind(tag=TAG).warning(f"声纹识别初始化失败: {str(e)}") From 755c81286cdd19f3f095f000f01ff75fafa426fc Mon Sep 17 00:00:00 2001 From: 3030332422 <3030332422@qq.com> Date: Mon, 8 Sep 2025 17:35:18 +0800 Subject: [PATCH 11/13] =?UTF-8?q?update:=E4=BF=AE=E6=94=B9vosk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/providers/asr/vosk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/xiaozhi-server/core/providers/asr/vosk.py b/main/xiaozhi-server/core/providers/asr/vosk.py index 7ec091b2..19d31822 100644 --- a/main/xiaozhi-server/core/providers/asr/vosk.py +++ b/main/xiaozhi-server/core/providers/asr/vosk.py @@ -13,8 +13,8 @@ logger = setup_logging() class ASRProvider(ASRProviderBase): def __init__(self, config: dict, delete_audio_file: bool = True): super().__init__() - self.interface_type = InterfaceType.NON_STREAM - self.model_path = config.get("model_path", "models/vosk/vosk-model-small-cn-0.22") + self.interface_type = InterfaceType.LOCAL + self.model_path = config.get("model_path") self.output_dir = config.get("output_dir", "tmp/") self.delete_audio_file = delete_audio_file From 9262963f207ec3d907ab532d8400762021efa0d4 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Mon, 8 Sep 2025 17:55:41 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E5=9C=A8=E4=B8=8D=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=A2=9D=E5=A4=96=E9=85=8D=E7=BD=AE=E7=9A=84=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=E8=BF=9B=E8=A1=8C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/connection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 6bbfbda9..324237dd 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -430,9 +430,9 @@ class ConnectionHandler: def _initialize_voiceprint(self): """为当前连接初始化声纹识别""" try: - voiceprint_enable = self.config.get("voiceprint", {}).get("enable", False) - if voiceprint_enable: - voiceprint_provider = VoiceprintProvider(self.config.get("voiceprint", {})) + voiceprint_config = self.config.get("voiceprint", {}) + if voiceprint_config: + voiceprint_provider = VoiceprintProvider(voiceprint_config) if voiceprint_provider is not None and voiceprint_provider.enabled: self.voiceprint_provider = voiceprint_provider self.logger.bind(tag=TAG).info("声纹识别功能已在连接时动态启用") From aef6d5dc1db848499f2067afcef1446a08f0dc53 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Mon, 8 Sep 2025 17:55:48 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E5=9C=A8=E4=B8=8D=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=A2=9D=E5=A4=96=E9=85=8D=E7=BD=AE=E7=9A=84=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=E8=BF=9B=E8=A1=8C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/config.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index 5a78bea2..8c6897b5 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -144,7 +144,6 @@ plugins: # 声纹识别配置 voiceprint: - enable: false # 声纹接口地址 url: # 说话人配置:speaker_id,名称,描述 @@ -914,4 +913,4 @@ TTS: audio_format: "pcm" # 默认音色,如需其他音色可到项目assets文件夹下注册 voice: "jay_klee" - output_dir: tmp/ \ No newline at end of file + output_dir: tmp/