mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 01:23:55 +08:00
Merge branch 'py_test_tts' of https://github.com/xinnan-tech/xiaozhi-esp32-server into py_test_tts
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';
|
||||||
@@ -240,6 +240,13 @@ databaseChangeLog:
|
|||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202506261637.sql
|
path: classpath:db/changelog/202506261637.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202507101201
|
||||||
|
author: luruxian
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202507101201.sql
|
||||||
- changeSet:
|
- changeSet:
|
||||||
id: 202507071130
|
id: 202507071130
|
||||||
author: cgd
|
author: cgd
|
||||||
|
|||||||
@@ -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