import uuid import json import base64 import requests from config.logger import setup_logging from core.utils.util import check_model_key from core.providers.tts.base import TTSProviderBase from core.utils.tts import convert_percentage_to_range TAG = __name__ logger = setup_logging() class TTSProvider(TTSProviderBase): TTS_PARAM_CONFIG = [ ("ttsVolume", "volume_ratio", 0.1, 3, 1.0, lambda v: round(float(v), 1)), ("ttsRate", "speed_ratio", 0.2, 3, 1.0, lambda v: round(float(v), 1)), ("ttsPitch", "pitch_ratio", 0.1, 3, 1.0, lambda v: round(float(v), 1)), ] def __init__(self, config, delete_audio_file): super().__init__(config, delete_audio_file) if config.get("appid"): self.appid = int(config.get("appid")) else: self.appid = "" self.access_token = config.get("access_token") self.cluster = config.get("cluster") if config.get("private_voice"): self.voice = config.get("private_voice") else: self.voice = config.get("voice") # 处理空字符串的情况 speed_ratio = config.get("speed_ratio", "1.0") volume_ratio = config.get("volume_ratio", "1.0") pitch_ratio = config.get("pitch_ratio", "1.0") self.audio_file_type = config.get("format", "wav") self.speed_ratio = float(speed_ratio) if speed_ratio else 1.0 self.volume_ratio = float(volume_ratio) if volume_ratio else 1.0 self.pitch_ratio = float(pitch_ratio) if pitch_ratio else 1.0 # 应用百分比调整(如果存在),否则使用公有化配置 self._apply_percentage_params(config) self.api_url = config.get("api_url") self.authorization = config.get("authorization") self.header = {"Authorization": f"{self.authorization}{self.access_token}"} model_key_msg = check_model_key("TTS", self.access_token) if model_key_msg: logger.bind(tag=TAG).error(model_key_msg) async def text_to_speak(self, text, output_file): request_json = { "app": { "appid": f"{self.appid}", "token": self.access_token, "cluster": self.cluster, }, "user": {"uid": "1"}, "audio": { "voice_type": self.voice, "encoding": self.audio_file_type, "speed_ratio": self.speed_ratio, "volume_ratio": self.volume_ratio, "pitch_ratio": self.pitch_ratio, }, "request": { "reqid": str(uuid.uuid4()), "text": text, "text_type": "plain", "operation": "query", "with_frontend": 1, "frontend_type": "unitTson", }, } try: resp = requests.post( self.api_url, json.dumps(request_json), headers=self.header ) if "data" in resp.json(): data = resp.json()["data"] audio_bytes = base64.b64decode(data) if output_file: with open(output_file, "wb") as file_to_save: file_to_save.write(audio_bytes) else: return audio_bytes else: raise Exception( f"{__name__} status_code: {resp.status_code} response: {resp.content}" ) except Exception as e: raise Exception(f"{__name__} error: {e}")