From e93053d4122b98368f5b1e8c3e8a88297414ffc1 Mon Sep 17 00:00:00 2001 From: Sakura-RanChen <1908198662@qq.com> Date: Wed, 23 Jul 2025 14:35:59 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=96=87=E6=9C=AC=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/core/connection.py | 10 ++++-- .../core/handle/sendAudioHandle.py | 4 +-- .../core/providers/tts/aliyun_stream.py | 36 ++++++++----------- .../providers/tts/huoshan_double_stream.py | 1 - .../core/providers/tts/linkerai.py | 1 - main/xiaozhi-server/core/utils/textUtils.py | 33 ++++++++++------- 6 files changed, 46 insertions(+), 39 deletions(-) diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index ba9279de..6d8fc11e 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -132,6 +132,8 @@ class ConnectionHandler: # tts相关变量 self.sentence_id = None + # 处理TTS响应没有文本返回 + self.tts_MessageText = "" # iot相关变量 self.iot_descriptors = {} @@ -785,8 +787,10 @@ class ConnectionHandler: if not bHasError: # 如需要大模型先处理一轮,添加相关处理后的日志情况 if len(response_message) > 0: + text_buff = "".join(response_message) + self.tts_MessageText = text_buff self.dialogue.put( - Message(role="assistant", content="".join(response_message)) + Message(role="assistant", content=text_buff) ) response_message.clear() self.logger.bind(tag=TAG).debug( @@ -809,8 +813,10 @@ class ConnectionHandler: # 存储对话内容 if len(response_message) > 0: + text_buff = "".join(response_message) + self.tts_MessageText = text_buff self.dialogue.put( - Message(role="assistant", content="".join(response_message)) + Message(role="assistant", content=text_buff) ) if depth == 0: self.tts.tts_text_queue.put( diff --git a/main/xiaozhi-server/core/handle/sendAudioHandle.py b/main/xiaozhi-server/core/handle/sendAudioHandle.py index 1b123874..82c168d4 100644 --- a/main/xiaozhi-server/core/handle/sendAudioHandle.py +++ b/main/xiaozhi-server/core/handle/sendAudioHandle.py @@ -12,7 +12,7 @@ async def sendAudioMessage(conn, sentenceType, audios, text): conn.logger.bind(tag=TAG).info(f"发送音频消息: {sentenceType}, {text}") pre_buffer = False - if conn.tts.tts_audio_first_sentence and text is not None: + if conn.tts.tts_audio_first_sentence: conn.logger.bind(tag=TAG).info(f"发送第一段语音: {text}") conn.tts.tts_audio_first_sentence = False pre_buffer = True @@ -73,7 +73,7 @@ async def send_tts_message(conn, state, text=None): """发送 TTS 状态消息""" message = {"type": "tts", "state": state, "session_id": conn.session_id} if text is not None: - message["text"] = text + message["text"] = textUtils.check_emoji(text) # TTS播放结束 if state == "stop": diff --git a/main/xiaozhi-server/core/providers/tts/aliyun_stream.py b/main/xiaozhi-server/core/providers/tts/aliyun_stream.py index 2a2a6891..0131fcfd 100644 --- a/main/xiaozhi-server/core/providers/tts/aliyun_stream.py +++ b/main/xiaozhi-server/core/providers/tts/aliyun_stream.py @@ -127,8 +127,6 @@ class TTSProvider(TTSProviderBase): # 专属tts设置 self.message_id = "" - self.tts_text = "" - self.text_buffer = [] # 创建Opus编码器 self.opus_encoder = opus_encoder_utils.OpusEncoderUtils( @@ -229,7 +227,6 @@ class TTSProvider(TTSProviderBase): # aliyunStream独有的参数生成 self.message_id = str(uuid.uuid4().hex) - self.text_buffer = [] logger.bind(tag=TAG).info("开始启动TTS会话...") future = asyncio.run_coroutine_threadsafe( @@ -250,7 +247,6 @@ class TTSProvider(TTSProviderBase): logger.bind(tag=TAG).debug( f"开始发送TTS文本: {message.content_detail}" ) - self.text_buffer.append(message.content_detail) future = asyncio.run_coroutine_threadsafe( self.text_to_speak(message.content_detail, None), loop=self.conn.loop, @@ -275,9 +271,6 @@ class TTSProvider(TTSProviderBase): if message.sentence_type == SentenceType.LAST: try: logger.bind(tag=TAG).info("开始结束TTS会话...") - self.tts_text = textUtils.get_string_no_punctuation_or_emoji( - "".join(self.text_buffer).replace("\n", "") - ) future = asyncio.run_coroutine_threadsafe( self.finish_session(self.conn.sentence_id), loop=self.conn.loop, @@ -444,34 +437,35 @@ class TTSProvider(TTSProviderBase): event_name = header.get("name") if event_name == "SynthesisStarted": logger.bind(tag=TAG).debug("TTS合成已启动") - elif event_name == "SentenceBegin": - logger.bind(tag=TAG).debug( - f"句子语音生成开始: {self.tts_text}" - ) - opus_datas_cache = [] self.tts_audio_queue.put( - (SentenceType.FIRST, [], self.tts_text) + (SentenceType.FIRST, [], None) ) + elif event_name == "SentenceBegin": + opus_datas_cache = [] elif event_name == "SentenceEnd": - logger.bind(tag=TAG).info( - f"句子语音生成成功: {self.tts_text}" - ) if ( not is_first_sentence or first_sentence_segment_count > 10 ): # 发送缓存的数据 - self.tts_audio_queue.put( - (SentenceType.MIDDLE, opus_datas_cache, None) - ) + if self.conn.tts_MessageText: + logger.bind(tag=TAG).info( + f"句子语音生成成功: {self.conn.tts_MessageText}" + ) + self.tts_audio_queue.put( + (SentenceType.MIDDLE, opus_datas_cache, self.conn.tts_MessageText) + ) + self.conn.tts_MessageText = None + else: + self.tts_audio_queue.put( + (SentenceType.MIDDLE, opus_datas_cache, None) + ) # 第一句话结束后,将标志设置为False is_first_sentence = False elif event_name == "SynthesisCompleted": logger.bind(tag=TAG).debug(f"会话结束~~") self._process_before_stop_play_files() session_finished = True - self.reuse_judgment = time.time() - self.tts_text = "" break except json.JSONDecodeError: logger.bind(tag=TAG).warning("收到无效的JSON消息") diff --git a/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py b/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py index 82cba035..ea7f18fd 100644 --- a/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py +++ b/main/xiaozhi-server/core/providers/tts/huoshan_double_stream.py @@ -232,7 +232,6 @@ class TTSProvider(TTSProviderBase): loop=self.conn.loop, ) future.result() - self.tts_audio_first_sentence = True self.before_stop_play_files.clear() logger.bind(tag=TAG).info("TTS会话启动成功") except Exception as e: diff --git a/main/xiaozhi-server/core/providers/tts/linkerai.py b/main/xiaozhi-server/core/providers/tts/linkerai.py index 1046b972..d1be586c 100644 --- a/main/xiaozhi-server/core/providers/tts/linkerai.py +++ b/main/xiaozhi-server/core/providers/tts/linkerai.py @@ -52,7 +52,6 @@ class TTSProvider(TTSProviderBase): self.processed_chars = 0 self.tts_text_buff = [] self.segment_count = 0 - self.tts_audio_first_sentence = True self.before_stop_play_files.clear() elif ContentType.TEXT == message.content_type: self.tts_text_buff.append(message.content_detail) diff --git a/main/xiaozhi-server/core/utils/textUtils.py b/main/xiaozhi-server/core/utils/textUtils.py index dd876cfa..47677b99 100644 --- a/main/xiaozhi-server/core/utils/textUtils.py +++ b/main/xiaozhi-server/core/utils/textUtils.py @@ -24,6 +24,15 @@ EMOJI_MAP = { "😘": "kissy", "😏": "confident", } +EMOJI_RANGES = [ + (0x1F600, 0x1F64F), + (0x1F300, 0x1F5FF), + (0x1F680, 0x1F6FF), + (0x1F900, 0x1F9FF), + (0x1FA70, 0x1FAFF), + (0x2600, 0x26FF), + (0x2700, 0x27BF), +] def get_string_no_punctuation_or_emoji(s): @@ -65,18 +74,7 @@ def is_punctuation_or_emoji(char): } if char.isspace() or char in punctuation_set: return True - # 检查表情符号(保留原有逻辑) - code_point = ord(char) - emoji_ranges = [ - (0x1F600, 0x1F64F), - (0x1F300, 0x1F5FF), - (0x1F680, 0x1F6FF), - (0x1F900, 0x1F9FF), - (0x1FA70, 0x1FAFF), - (0x2600, 0x26FF), - (0x2700, 0x27BF), - ] - return any(start <= code_point <= end for start, end in emoji_ranges) + return is_emoji(char) async def get_emotion(conn, text): @@ -102,3 +100,14 @@ async def get_emotion(conn, text): except Exception as e: conn.logger.bind(tag=TAG).warning(f"发送情绪表情失败,错误:{e}") return + + +def is_emoji(char): + """检查字符是否为emoji表情""" + code_point = ord(char) + return any(start <= code_point <= end for start, end in EMOJI_RANGES) + + +def check_emoji(text): + """去除文本中的所有emoji表情""" + return ''.join(char for char in text if not is_emoji(char) and char != "\n")