mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 01:23:55 +08:00
添加百度asr支持
This commit is contained in:
@@ -258,6 +258,19 @@ ASR:
|
|||||||
access_key_id: 你的阿里云账号access_key_id
|
access_key_id: 你的阿里云账号access_key_id
|
||||||
access_key_secret: 你的阿里云账号access_key_secret
|
access_key_secret: 你的阿里云账号access_key_secret
|
||||||
output_dir: tmp/
|
output_dir: tmp/
|
||||||
|
BaiduASR:
|
||||||
|
# 可以在这里申请百度语音技术的AppID、API Key、Secret Key
|
||||||
|
# https://console.bce.baidu.com/ai-engine/old/#/ai/speech/app/list
|
||||||
|
# 启用前需要先安装依赖包:
|
||||||
|
# pip install baidu-aip==4.16.13
|
||||||
|
# pip install chardet==5.2.0
|
||||||
|
type: baidu
|
||||||
|
app_id: 你的百度语音技术AppID
|
||||||
|
api_key: 你的百度语音技术APIKey
|
||||||
|
secret_key: 你的百度语音技术SecretKey
|
||||||
|
# 语言参数,1537为普通话,具体参考:https://ai.baidu.com/ai-doc/SPEECH/0lbxfnc9b
|
||||||
|
dev_pid: 1537
|
||||||
|
output_dir: tmp/
|
||||||
|
|
||||||
VAD:
|
VAD:
|
||||||
SileroVAD:
|
SileroVAD:
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
import os
|
||||||
|
import uuid
|
||||||
|
from typing import Optional, Tuple, List
|
||||||
|
import wave
|
||||||
|
import opuslib_next
|
||||||
|
|
||||||
|
from aip import AipSpeech
|
||||||
|
from core.providers.asr.base import ASRProviderBase
|
||||||
|
from config.logger import setup_logging
|
||||||
|
|
||||||
|
TAG = __name__
|
||||||
|
logger = setup_logging()
|
||||||
|
|
||||||
|
class ASRProvider(ASRProviderBase):
|
||||||
|
def __init__(self, config: dict, delete_audio_file: bool = True):
|
||||||
|
self.app_id = config.get("app_id")
|
||||||
|
self.api_key = config.get("api_key")
|
||||||
|
self.secret_key = config.get("secret_key")
|
||||||
|
self.dev_pid = config.get("dev_pid")
|
||||||
|
self.output_dir = config.get("output_dir")
|
||||||
|
self.delete_audio_file = delete_audio_file
|
||||||
|
|
||||||
|
self.client = AipSpeech(str(self.app_id), self.api_key, self.secret_key)
|
||||||
|
|
||||||
|
# 确保输出目录存在
|
||||||
|
os.makedirs(self.output_dir, exist_ok=True)
|
||||||
|
|
||||||
|
def save_audio_to_file(self, pcm_data: List[bytes], session_id: str) -> str:
|
||||||
|
"""PCM数据保存为WAV文件"""
|
||||||
|
module_name = __name__.split(".")[-1]
|
||||||
|
file_name = f"asr_{module_name}_{session_id}_{uuid.uuid4()}.wav"
|
||||||
|
file_path = os.path.join(self.output_dir, file_name)
|
||||||
|
|
||||||
|
with wave.open(file_path, "wb") as wf:
|
||||||
|
wf.setnchannels(1)
|
||||||
|
wf.setsampwidth(2) # 2 bytes = 16-bit
|
||||||
|
wf.setframerate(16000)
|
||||||
|
wf.writeframes(b"".join(pcm_data))
|
||||||
|
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def decode_opus(opus_data: List[bytes]) -> bytes:
|
||||||
|
"""将Opus音频数据解码为PCM数据"""
|
||||||
|
|
||||||
|
decoder = opuslib_next.Decoder(16000, 1) # 16kHz, 单声道
|
||||||
|
pcm_data = []
|
||||||
|
|
||||||
|
for opus_packet in opus_data:
|
||||||
|
try:
|
||||||
|
pcm_frame = decoder.decode(opus_packet, 960) # 960 samples = 60ms
|
||||||
|
pcm_data.append(pcm_frame)
|
||||||
|
except opuslib_next.OpusError as e:
|
||||||
|
logger.bind(tag=TAG).error(f"Opus解码错误: {e}", exc_info=True)
|
||||||
|
|
||||||
|
return pcm_data
|
||||||
|
|
||||||
|
async def speech_to_text(self, opus_data: List[bytes], session_id: str) -> Tuple[Optional[str], Optional[str]]:
|
||||||
|
"""将语音数据转换为文本"""
|
||||||
|
if not opus_data:
|
||||||
|
logger.bind(tag=TAG).warn("音频数据为空!")
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
file_path = None
|
||||||
|
try:
|
||||||
|
# 检查配置是否已设置
|
||||||
|
if not self.app_id or not self.api_key or not self.secret_key:
|
||||||
|
logger.bind(tag=TAG).error("百度语音识别配置未设置,无法进行识别")
|
||||||
|
return None, file_path
|
||||||
|
|
||||||
|
# 将Opus音频数据解码为PCM
|
||||||
|
pcm_data = self.decode_opus(opus_data)
|
||||||
|
combined_pcm_data = b"".join(pcm_data)
|
||||||
|
|
||||||
|
# 判断是否保存为WAV文件
|
||||||
|
if self.delete_audio_file:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.save_audio_to_file(pcm_data, session_id)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
# 识别本地文件
|
||||||
|
result = self.client.asr(combined_pcm_data, 'pcm', 16000, {
|
||||||
|
'dev_pid': str(self.dev_pid),
|
||||||
|
})
|
||||||
|
|
||||||
|
if result and result["err_no"] == 0:
|
||||||
|
logger.bind(tag=TAG).debug(f"百度语音识别耗时: {time.time() - start_time:.3f}s | 结果: {result}")
|
||||||
|
result = result["result"][0]
|
||||||
|
return result, file_path
|
||||||
|
else:
|
||||||
|
raise Exception(f"百度语音识别失败,错误码: {result['err_no']},错误信息: {result['err_msg']}")
|
||||||
|
return None, file_path
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.bind(tag=TAG).error(f"处理音频时发生错误!{e}", exc_info=True)
|
||||||
|
return None, file_path
|
||||||
@@ -25,4 +25,6 @@ sherpa_onnx==1.11.0
|
|||||||
mcp==1.4.1
|
mcp==1.4.1
|
||||||
cnlunar==0.2.0
|
cnlunar==0.2.0
|
||||||
PySocks==1.7.1
|
PySocks==1.7.1
|
||||||
dashscope==1.23.1
|
dashscope==1.23.1
|
||||||
|
baidu-aip==4.16.13
|
||||||
|
chardet==5.2.0
|
||||||
Reference in New Issue
Block a user