mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 15:13:55 +08:00
test
This commit is contained in:
@@ -713,4 +713,11 @@ TTS:
|
||||
headers: # 自定义请求头
|
||||
# Authorization: Bearer xxxx
|
||||
format: mp3 # 接口返回的音频格式
|
||||
output_dir: tmp/
|
||||
LinkeraiTTS:
|
||||
#各参数意义见开发文档:https://tts.linkerai.top/docs#/default/text_to_speech_tts_get
|
||||
type: linkerai
|
||||
api_url: https://tts.linkerai.top/tts
|
||||
access_token: "test"
|
||||
voice: "OUeAo1mhq6IBExi"
|
||||
output_dir: tmp/
|
||||
@@ -0,0 +1,95 @@
|
||||
from core.providers.tts.base import TTSProviderBase
|
||||
from core.providers.tts.dto.dto import (
|
||||
TTSMessageDTO,
|
||||
SentenceType,
|
||||
ContentType,
|
||||
InterfaceType
|
||||
)
|
||||
from config.logger import setup_logging
|
||||
from core.utils import opus_encoder_utils
|
||||
import requests
|
||||
|
||||
TAG = __name__
|
||||
logger = setup_logging()
|
||||
|
||||
|
||||
class TTSProvider(TTSProviderBase):
|
||||
def __init__(self, config, delete_audio_file):
|
||||
super().__init__(config, delete_audio_file)
|
||||
self.interface_type = InterfaceType.SINGLE_STREAM
|
||||
self.access_token = config.get("access_token")
|
||||
self.voice = config.get("voice")
|
||||
self.api_url = config.get("api_url")
|
||||
|
||||
# 根据配置选择音频格式,优先使用opus
|
||||
self.audio_format = config.get("audio_format", "opus")
|
||||
|
||||
# 创建Opus编码器
|
||||
self.opus_encoder = opus_encoder_utils.OpusEncoderUtils(
|
||||
sample_rate=16000,
|
||||
channels=1,
|
||||
frame_size_ms=60
|
||||
)
|
||||
|
||||
async def text_to_speak(self, text, _):
|
||||
"""将文本转换为语音(流式)"""
|
||||
await self.send_text(self.voice, text)
|
||||
return
|
||||
|
||||
async def send_text(self, speaker: str, text: str):
|
||||
"""向 TTS 服务发送文本并获取音频流"""
|
||||
try:
|
||||
# 构造请求参数
|
||||
params = {
|
||||
"tts_text": text,
|
||||
"spk_id": self.voice,
|
||||
"frame_duration": 60,
|
||||
"stream": "true",
|
||||
"target_sr": 16000,
|
||||
"audio_format": self.audio_format,
|
||||
}
|
||||
|
||||
# 构造请求头
|
||||
headers = {
|
||||
"Authorization": f"Bearer {self.access_token}",
|
||||
}
|
||||
|
||||
# 发送流式请求
|
||||
response = requests.get(
|
||||
self.api_url,
|
||||
params=params,
|
||||
headers=headers,
|
||||
stream=True
|
||||
)
|
||||
|
||||
# 检查响应状态
|
||||
if response.status_code != 200:
|
||||
logger.bind(tag=TAG).error(f"TTS 请求失败: {response.status_code}, {response.text}")
|
||||
return
|
||||
|
||||
# 处理音频流
|
||||
audio_frames = []
|
||||
for chunk in response.iter_content(chunk_size=1024):
|
||||
if chunk:
|
||||
if self.audio_format == "pcm":
|
||||
# 将PCM转换为Opus
|
||||
opus_frames = self.opus_encoder.encode_pcm_to_opus(chunk, False)
|
||||
audio_frames.extend(opus_frames)
|
||||
else:
|
||||
# 直接使用Opus帧
|
||||
audio_frames.append(chunk)
|
||||
|
||||
# 将音频帧放入队列
|
||||
self.tts_audio_queue.put(
|
||||
(SentenceType.MIDDLE, audio_frames, text)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.bind(tag=TAG).error(f"TTS 流式处理异常:{str(e)}")
|
||||
raise
|
||||
|
||||
async def close(self):
|
||||
"""资源清理方法"""
|
||||
await super().close()
|
||||
if hasattr(self, "opus_encoder"):
|
||||
self.opus_encoder.close()
|
||||
Reference in New Issue
Block a user