Merge pull request #2995 from xinnan-tech/py_fix_HuoShanTTS

Py fix huo shan tts
This commit is contained in:
wengzh
2026-03-12 16:25:47 +08:00
committed by GitHub
8 changed files with 38 additions and 15 deletions
+1 -1
View File
@@ -189,7 +189,7 @@ export default {
'editVoiceDialog.remarkPlaceholder': '请输入备注内容',
'editVoiceDialog.generatePreview': '生成试听',
'editVoiceDialog.defaultVoiceName': '湾湾小何',
'editVoiceDialog.defaultLanguageType': '中文',
'editVoiceDialog.defaultLanguageType': '普通话',
'editVoiceDialog.requiredVoiceCode': '请输入音色编码',
'editVoiceDialog.requiredVoiceName': '请输入音色名称',
+1 -1
View File
@@ -189,7 +189,7 @@ export default {
'editVoiceDialog.remarkPlaceholder': '請輸入備註內容',
'editVoiceDialog.generatePreview': '生成試聽',
'editVoiceDialog.defaultVoiceName': '灣灣小何',
'editVoiceDialog.defaultLanguageType': '中文',
'editVoiceDialog.defaultLanguageType': '普通話',
'editVoiceDialog.requiredVoiceCode': '請輸入音色編碼',
'editVoiceDialog.requiredVoiceName': '請輸入音色名稱',
@@ -21,7 +21,6 @@ async def sendAudioMessage(conn: "ConnectionHandler", sentenceType, audios, text
if conn.tts.tts_audio_first_sentence:
conn.logger.bind(tag=TAG).info(f"发送第一段语音: {text}")
conn.tts.tts_audio_first_sentence = False
await send_tts_message(conn, "start", None)
if sentenceType == SentenceType.FIRST:
# 同一句子的后续消息加入流控队列,其他情况立即发送
@@ -204,7 +203,6 @@ def _start_background_sender(conn: "ConnectionHandler", rate_controller, flow_co
conn.last_activity_time = time.time() * 1000
await _do_send_audio(conn, packet, flow_control)
conn.client_is_speaking = True
# 使用 start_sending 启动后台循环
rate_controller.start_sending(send_callback)
@@ -232,12 +230,10 @@ async def _send_audio_with_rate_control(
# 预缓冲:前N个包直接发送
if flow_control["packet_count"] < PRE_BUFFER_COUNT:
await _do_send_audio(conn, packet, flow_control)
conn.client_is_speaking = True
elif send_delay > 0:
# 固定延迟模式
await asyncio.sleep(send_delay)
await _do_send_audio(conn, packet, flow_control)
conn.client_is_speaking = True
else:
# 动态流控模式:仅添加到队列,由后台循环负责发送
rate_controller.add_audio(packet)
@@ -318,3 +314,5 @@ async def send_stt_message(conn: "ConnectionHandler", text):
json.dumps({"type": "stt", "text": stt_text, "session_id": conn.session_id})
)
await send_tts_message(conn, "start")
# 发送start消息后客户端状态会处于说话中状态,同步服务端状态
conn.client_is_speaking = True
@@ -33,6 +33,7 @@ class TTSProvider(TTSProviderBase):
self.api_key = config.get("api_key")
if not self.api_key:
raise ValueError("api_key is required for CosyVoice TTS")
self.report_on_last = True
# WebSocket配置
self.ws_url = "wss://dashscope.aliyuncs.com/api-ws/v1/inference/"
@@ -104,6 +104,7 @@ class TTSProvider(TTSProviderBase):
self.access_key_secret = config.get("access_key_secret")
self.appkey = config.get("appkey")
self.format = config.get("format", "pcm")
self.report_on_last = True
# 音色配置 - CosyVoice大模型音色
if config.get("private_voice"):
+18 -7
View File
@@ -40,6 +40,7 @@ class TTSProviderBase(ABC):
self.tts_audio_queue = queue.Queue()
self.tts_audio_first_sentence = True
self.before_stop_play_files = []
self.report_on_last = False
self.tts_text_buff = []
self.punctuations = (
@@ -322,7 +323,7 @@ class TTSProviderBase(ABC):
def _audio_play_priority_thread(self):
# 需要上报的文本和音频列表
enqueue_text = None
enqueue_audio = None
enqueue_audio = []
while not self.conn.stop_event.is_set():
text = None
try:
@@ -342,14 +343,24 @@ class TTSProviderBase(ABC):
# 收到下一个文本开始或会话结束时进行上报
if sentence_type is not SentenceType.MIDDLE:
# 上报TTS数据
if enqueue_text is not None and enqueue_audio is not None:
enqueue_tts_report(self.conn, enqueue_text, enqueue_audio)
enqueue_audio = []
enqueue_text = text
if self.report_on_last:
# 累积模式:适用于全程只有一个语音流的TTS(如seed-tts-2.0
# FIRST时只记录文本,音频持续累积,仅在LAST时统一上报
if text:
enqueue_text = text
if sentence_type == SentenceType.LAST:
enqueue_tts_report(self.conn, enqueue_text, enqueue_audio)
enqueue_audio = []
enqueue_text = None
else:
# 非累积模式:每个句子分别上报
if enqueue_text is not None:
enqueue_tts_report(self.conn, enqueue_text, enqueue_audio)
enqueue_audio = []
enqueue_text = text
# 收集上报音频数据
if isinstance(audio_datas, bytes) and enqueue_audio is not None:
if isinstance(audio_datas, bytes):
enqueue_audio.append(audio_datas)
# 发送音频
@@ -148,6 +148,8 @@ class TTSProvider(TTSProviderBase):
self.access_token = config.get("access_token")
self.cluster = config.get("cluster")
self.resource_id = config.get("resource_id")
self.resource_type = True if self.resource_id == "seed-tts-2.0" else False
self.report_on_last = self.resource_type
self.activate_session = False
if config.get("private_voice"):
self.voice = config.get("private_voice")
@@ -511,7 +513,7 @@ class TTSProvider(TTSProviderBase):
if res.optional.event == EVENT_SessionCanceled:
logger.bind(tag=TAG).debug(f"释放服务端资源成功~~")
self.activate_session = False
elif res.optional.event == EVENT_TTSSentenceStart:
elif not self.resource_type and res.optional.event == EVENT_TTSSentenceStart:
json_data = json.loads(res.payload.decode("utf-8"))
self.tts_text = json_data.get("text", "")
logger.bind(tag=TAG).debug(f"句子语音生成开始: {self.tts_text}")
@@ -522,8 +524,17 @@ class TTSProvider(TTSProviderBase):
res.optional.event == EVENT_TTSResponse
and res.header.message_type == AUDIO_ONLY_RESPONSE
):
# 处理seed-tts-2.0文本字幕
if self.resource_type and self.conn.tts_MessageText:
logger.bind(tag=TAG).info(
f"句子语音生成成功: {self.conn.tts_MessageText}"
)
self.tts_audio_queue.put(
(SentenceType.FIRST, [], self.conn.tts_MessageText)
)
self.conn.tts_MessageText = None
self.wav_to_opus_data_audio_raw_stream(res.payload, callback=self.handle_opus)
elif res.optional.event == EVENT_TTSSentenceEnd:
elif not self.resource_type and res.optional.event == EVENT_TTSSentenceEnd:
logger.bind(tag=TAG).info(f"句子语音生成成功:{self.tts_text}")
elif res.optional.event == EVENT_SessionFinished:
logger.bind(tag=TAG).debug(f"会话结束~~")
@@ -76,6 +76,7 @@ class TTSProvider(TTSProviderBase):
self.app_id = config.get("app_id")
self.api_key = config.get("api_key")
self.api_secret = config.get("api_secret")
self.report_on_last = True
# 接口地址
self.api_url = config.get("api_url", "wss://cbm01.cn-huabei-1.xf-yun.com/v1/private/mcd9m97e6")