From 2a9f809700e624125836d81e3b6e60f52242eea3 Mon Sep 17 00:00:00 2001 From: wengzh <1337326764@qq.com> Date: Mon, 27 Jul 2026 09:59:32 +0800 Subject: [PATCH] =?UTF-8?q?refactor(reportHandle):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=B8=8A=E6=8A=A5=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E9=80=82=E9=85=8D=E5=A4=9A=E6=A0=BC=E5=BC=8F=E9=9F=B3=E9=A2=91?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 重命名参数与变量,明确上报类型与音频格式 2. 拆分PCM和Opus转WAV逻辑,分别处理不同输入格式 3. 移动校验逻辑到上报队列函数开头,提前拦截无效上报 4. 完善Opus转WAV的解码与资源释放流程 --- .../core/handle/reportHandle.py | 97 +++++++++++++++---- 1 file changed, 79 insertions(+), 18 deletions(-) diff --git a/main/xiaozhi-server/core/handle/reportHandle.py b/main/xiaozhi-server/core/handle/reportHandle.py index ea621f74..15beb472 100644 --- a/main/xiaozhi-server/core/handle/reportHandle.py +++ b/main/xiaozhi-server/core/handle/reportHandle.py @@ -22,39 +22,45 @@ from config.manage_api_client import report as manage_report TAG = __name__ -async def report(conn: "ConnectionHandler", type, text, opus_data, report_time): +async def report(conn: "ConnectionHandler", chat_type, text, audio_data, report_time): """执行聊天记录上报操作 Args: conn: 连接对象 - type: 上报类型,1为用户,2为智能体,3为工具调用 + chat_type: 上报类型,1为用户(ASR/PCM),2为智能体(TTS/Opus),3为工具调用 text: 合成文本 - opus_data: opus音频数据 + audio_data: 音频数据(chat_type=1时为PCM格式,chat_type=2时为Opus格式) report_time: 上报时间 """ try: - if opus_data: - audio_data = opus_to_wav(conn, opus_data) + if audio_data: + + if chat_type == 1: + wav_data = pcm_to_wav(conn, audio_data) + elif chat_type == 2: + wav_data = opus_to_wav(conn, audio_data) + else: + wav_data = None else: - audio_data = None + wav_data = None # 执行异步上报 await manage_report( mac_address=conn.device_id, session_id=conn.session_id, - chat_type=type, + chat_type=chat_type, content=text, - audio=audio_data, + audio=wav_data, report_time=report_time, ) except Exception as e: conn.logger.bind(tag=TAG).error(f"聊天记录上报失败: {e}") -def opus_to_wav(conn: "ConnectionHandler", pcm_data): +def pcm_to_wav(conn: "ConnectionHandler", pcm_data): """将PCM数据转换为WAV格式的字节流 Args: - output_dir: 输出目录(保留参数以保持接口兼容) + conn: 连接对象 pcm_data: PCM音频数据(可能是列表或bytes) Returns: @@ -96,11 +102,62 @@ def opus_to_wav(conn: "ConnectionHandler", pcm_data): raise +def opus_to_wav(conn: "ConnectionHandler", opus_data): + """将Opus数据转换为WAV格式的字节流 + + Args: + conn: 连接对象 + opus_data: Opus音频数据(可能是列表或bytes) + + Returns: + bytes: WAV格式的音频数据 + """ + decoder = None + try: + decoder = opuslib_next.Decoder(16000, 1) + pcm_data = [] + + if isinstance(opus_data, list): + for opus_packet in opus_data: + try: + pcm_frame = decoder.decode(opus_packet, 960) + pcm_data.append(pcm_frame) + except opuslib_next.OpusError as e: + conn.logger.bind(tag=TAG).error(f"Opus解码错误: {e}", exc_info=True) + elif isinstance(opus_data, bytes): + pcm_frame = decoder.decode(opus_data, 960) + pcm_data.append(pcm_frame) + + if not pcm_data: + raise ValueError("没有有效的音频数据") + + pcm_data_bytes = b"".join(pcm_data) + + wav_header = bytearray() + wav_header.extend(b"RIFF") + wav_header.extend((36 + len(pcm_data_bytes)).to_bytes(4, "little")) + wav_header.extend(b"WAVE") + wav_header.extend(b"fmt ") + wav_header.extend((16).to_bytes(4, "little")) + wav_header.extend((1).to_bytes(2, "little")) + wav_header.extend((1).to_bytes(2, "little")) + wav_header.extend((16000).to_bytes(4, "little")) + wav_header.extend((32000).to_bytes(4, "little")) + wav_header.extend((2).to_bytes(2, "little")) + wav_header.extend((16).to_bytes(2, "little")) + wav_header.extend(b"data") + wav_header.extend(len(pcm_data_bytes).to_bytes(4, "little")) + + return bytes(wav_header) + pcm_data_bytes + finally: + if decoder is not None: + try: + del decoder + except Exception as e: + conn.logger.bind(tag=TAG).debug(f"释放decoder资源时出错: {e}") + + def enqueue_tts_report(conn: "ConnectionHandler", text, opus_data): - if not conn.read_config_from_api or conn.need_bind or not conn.report_tts_enable: - return - if conn.chat_history_conf == 0: - return """将TTS数据加入上报队列 Args: @@ -108,6 +165,10 @@ def enqueue_tts_report(conn: "ConnectionHandler", text, opus_data): text: 合成文本 opus_data: opus音频数据 """ + if not conn.read_config_from_api or conn.need_bind or not conn.report_tts_enable: + return + if conn.chat_history_conf == 0: + return try: # 使用连接对象的队列,传入文本和二进制数据而非文件路径 if conn.chat_history_conf == 2: @@ -164,10 +225,6 @@ def enqueue_tool_report(conn: "ConnectionHandler", tool_name: str, tool_input: d def enqueue_asr_report(conn: "ConnectionHandler", text, opus_data): - if not conn.read_config_from_api or conn.need_bind or not conn.report_asr_enable: - return - if conn.chat_history_conf == 0: - return """将ASR数据加入上报队列 Args: @@ -175,6 +232,10 @@ def enqueue_asr_report(conn: "ConnectionHandler", text, opus_data): text: 合成文本 opus_data: opus音频数据 """ + if not conn.read_config_from_api or conn.need_bind or not conn.report_asr_enable: + return + if conn.chat_history_conf == 0: + return try: # 使用连接对象的队列,传入文本和二进制数据而非文件路径 if conn.chat_history_conf == 2: