From fbd4a22e3e8d34e8fa887f4170e402508330068f Mon Sep 17 00:00:00 2001 From: luruxian Date: Thu, 10 Jul 2025 11:41:20 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(asr):=20=E6=B7=BB=E5=8A=A0OpenAI?= =?UTF-8?q?=E5=92=8CGroq=E8=AF=AD=E9=9F=B3=E8=AF=86=E5=88=AB=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增GPT语音识别模型供应器和配置,实现语音转文本功能 更新相关文档说明,包含API申请步骤和使用注意事项 --- .../resources/db/changelog/202507101201.sql | 31 +++++++ main/xiaozhi-server/core/providers/asr/gpt.py | 82 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 main/manager-api/src/main/resources/db/changelog/202507101201.sql create mode 100644 main/xiaozhi-server/core/providers/asr/gpt.py diff --git a/main/manager-api/src/main/resources/db/changelog/202507101201.sql b/main/manager-api/src/main/resources/db/changelog/202507101201.sql new file mode 100644 index 00000000..14bd6725 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202507101201.sql @@ -0,0 +1,31 @@ +-- OpenAI ASR模型供应器 +delete from `ai_model_provider` where id = 'SYSTEM_ASR_GptASR'; +INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES +('SYSTEM_ASR_GptASR', 'ASR', 'gpt', 'Gpt语音识别', '[{"key": "base_url", "type": "string", "label": "基础URL"}, {"key": "model_name", "type": "string", "label": "模型名称"}, {"key": "api_key", "type": "string", "label": "API密钥"}, {"key": "output_dir", "type": "string", "label": "输出目录"}]', 5, 1, NOW(), 1, NOW()); + + +-- OpenAI ASR模型配置 +delete from `ai_model_config` where id = 'ASR_GptASR'; +INSERT INTO `ai_model_config` VALUES ('ASR_GptASR', 'ASR', 'GptASR', 'GPT语音识别', 0, 1, '{\"type\": \"gpt\", \"api_key\": \"\", \"base_url\": \"https://api.openai.com/v1/audio/transcriptions\", \"model_name\": \"gpt-4o-mini-transcribe\", \"output_dir\": \"tmp/\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL); + + +-- 更新OpenAI ASR配置说明 +UPDATE `ai_model_config` SET +`doc_link` = 'https://platform.openai.com/docs/api-reference/audio/createTranscription', +`remark` = 'OpenAI ASR配置说明: +1. 需要在OpenAI开放平台创建组织并获取api_key +2. 支持中、英、日、韩等多种语音识别,具体参考文档https://platform.openai.com/docs/guides/speech-to-text +3. 需要网络连接 +4. 输出文件保存在tmp/目录 +5. 兼容groq语音识别。 groq识别速度更快。具体参考文档:https://console.groq.com/docs/speech-to-text +申请步骤: +**OpenAi ASR申请步骤:** +1.登录OpenAI Platform。https://auth.openai.com/log-in +2.创建api-key https://platform.openai.com/settings/organization/api-keys +3.模型可以选择gpt-4o-transcribe或GPT-4o mini Transcribe +**groq ASR申请步骤:** +1.登录groq Console。https://console.groq.com/home +2.创建api-key https://console.groq.com/keys +3.模型可以选择whisper-large-v3-turbo或whisper-large-v3(distil-whisper-large-v3-en仅支持英语转录) +4.base url https://api.groq.com/openai/v1/audio/transcriptions +' WHERE `id` = 'ASR_GptASR'; \ No newline at end of file diff --git a/main/xiaozhi-server/core/providers/asr/gpt.py b/main/xiaozhi-server/core/providers/asr/gpt.py new file mode 100644 index 00000000..5c6e849c --- /dev/null +++ b/main/xiaozhi-server/core/providers/asr/gpt.py @@ -0,0 +1,82 @@ +import time +import os +from config.logger import setup_logging +from typing import Optional, Tuple, List +from core.providers.asr.dto.dto import InterfaceType +from core.providers.asr.base import ASRProviderBase + +import requests + +TAG = __name__ +logger = setup_logging() + +class ASRProvider(ASRProviderBase): + def __init__(self, config: dict, delete_audio_file: bool): + self.interface_type = InterfaceType.NON_STREAM + self.api_key = config.get("api_key") + self.api_url = config.get("base_url") + self.model = config.get("model_name") + self.output_dir = config.get("output_dir") + self.delete_audio_file = delete_audio_file + + os.makedirs(self.output_dir, exist_ok=True) + + async def speech_to_text(self, opus_data: List[bytes], session_id: str, audio_format="opus") -> Tuple[Optional[str], Optional[str]]: + file_path = None + try: + start_time = time.time() + if audio_format == "pcm": + pcm_data = opus_data + else: + pcm_data = self.decode_opus(opus_data) + file_path = self.save_audio_to_file(pcm_data, session_id) + + logger.bind(tag=TAG).debug( + f"音频文件保存耗时: {time.time() - start_time:.3f}s | 路径: {file_path}" + ) + + logger.bind(tag=TAG).info(f"file path: {file_path}") + headers = { + "Authorization": f"Bearer {self.api_key}", + } + + # 使用data参数传递模型名称 + data = { + "model": self.model + } + + + with open(file_path, "rb") as audio_file: # 使用with语句确保文件关闭 + files = { + "file": audio_file + } + + start_time = time.time() + response = requests.post( + self.api_url, + files=files, + data=data, + headers=headers + ) + logger.bind(tag=TAG).debug( + f"语音识别耗时: {time.time() - start_time:.3f}s | 结果: {response.text}" + ) + + if response.status_code == 200: + text = response.json().get("text", "") + return text, file_path + else: + raise Exception(f"API请求失败: {response.status_code} - {response.text}") + + except Exception as e: + logger.bind(tag=TAG).error(f"语音识别失败: {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 b2e6156bbbe982715b96c947abb2399530dd32db Mon Sep 17 00:00:00 2001 From: luruxian Date: Thu, 10 Jul 2025 11:44:49 +0800 Subject: [PATCH 2/2] =?UTF-8?q?chore(db):=20=E6=B7=BB=E5=8A=A0=E6=96=B0?= =?UTF-8?q?=E7=9A=84=E6=95=B0=E6=8D=AE=E5=BA=93=E5=8F=98=E6=9B=B4=E9=9B=86?= =?UTF-8?q?202507101201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加新的数据库变更脚本202507101201.sql到变更日志中 --- .../main/resources/db/changelog/db.changelog-master.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 32ba9f30..5fc027dd 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 @@ -239,4 +239,11 @@ databaseChangeLog: changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202506261637.sql \ No newline at end of file + path: classpath:db/changelog/202506261637.sql + - changeSet: + id: 202507101201 + author: luruxian + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202507101201.sql \ No newline at end of file