import os
|
from typing import Optional, Tuple, List
|
import dashscope
|
from config.logger import setup_logging
|
from core.providers.asr.base import ASRProviderBase
|
from core.providers.asr.dto.dto import InterfaceType
|
|
tag = __name__
|
logger = setup_logging()
|
|
|
class ASRProvider(ASRProviderBase):
|
def __init__(self, config: dict, delete_audio_file: bool):
|
super().__init__()
|
# 音频文件上传类型,流式文本识别输出
|
self.interface_type = InterfaceType.NON_STREAM
|
"""Qwen3-ASR-Flash ASR初始化"""
|
|
# 配置参数
|
self.api_key = config.get("api_key")
|
if not self.api_key:
|
raise ValueError("Qwen3-ASR-Flash 需要配置 api_key")
|
|
self.model_name = config.get("model_name", "qwen3-asr-flash")
|
self.output_dir = config.get("output_dir", "./audio_output")
|
self.delete_audio_file = delete_audio_file
|
|
# ASR选项配置
|
self.enable_lid = config.get("enable_lid", True) # 自动语种检测
|
self.enable_itn = config.get("enable_itn", True) # 逆文本归一化
|
self.language = config.get("language", None) # 指定语种,默认自动检测
|
self.context = config.get("context", "") # 上下文信息,用于提高识别准确率
|
|
# 确保输出目录存在
|
os.makedirs(self.output_dir, exist_ok=True)
|
|
def prefers_temp_file(self) -> bool:
|
return True
|
|
def requires_file(self) -> bool:
|
return True
|
|
async def speech_to_text(
|
self, opus_data: List[bytes], session_id: str, artifacts=None
|
) -> Tuple[Optional[str], Optional[str]]:
|
"""将语音数据转换为文本"""
|
temp_file_path = None
|
file_path = None
|
try:
|
if artifacts is None:
|
return "", None
|
temp_file_path = artifacts.temp_path
|
file_path = artifacts.file_path
|
if not temp_file_path:
|
return "", file_path
|
# 构造请求消息
|
messages = [
|
{
|
"role": "user",
|
"content": [
|
{"audio": temp_file_path}
|
]
|
}
|
]
|
|
# 如果有上下文信息,添加system消息
|
if self.context:
|
messages.insert(0, {
|
"role": "system",
|
"content": [
|
{"text": self.context}
|
]
|
})
|
|
# 准备ASR选项
|
asr_options = {
|
"enable_lid": self.enable_lid,
|
"enable_itn": self.enable_itn
|
}
|
|
# 如果指定了语种,添加到选项中
|
if self.language:
|
asr_options["language"] = self.language
|
|
# 设置API密钥
|
dashscope.api_key = self.api_key
|
|
# 发送流式请求
|
response = dashscope.MultiModalConversation.call(
|
model=self.model_name,
|
messages=messages,
|
result_format="message",
|
asr_options=asr_options,
|
stream=True
|
)
|
|
# 处理流式响应
|
full_text = ""
|
for chunk in response:
|
try:
|
text = chunk["output"]["choices"][0]["message"].content[0]["text"]
|
# 更新为最新的完整文本
|
full_text = text.strip()
|
except:
|
pass
|
|
return full_text, file_path
|
|
except Exception as e:
|
logger.bind(tag=tag).error(f"语音识别失败: {e}")
|
return "", file_path
|