mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
feat(asr): 添加OpenAI和Groq语音识别支持
新增GPT语音识别模型供应器和配置,实现语音转文本功能 更新相关文档说明,包含API申请步骤和使用注意事项
This commit is contained in:
@@ -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';
|
||||
@@ -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}")
|
||||
|
||||
Reference in New Issue
Block a user