mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-24 08:03:53 +08:00
update:上报聊天音频
This commit is contained in:
@@ -4,7 +4,7 @@ from loguru import logger
|
||||
from config.config_loader import load_config
|
||||
from config.settings import check_config_file
|
||||
|
||||
SERVER_VERSION = "0.3.13"
|
||||
SERVER_VERSION = "0.3.14"
|
||||
|
||||
|
||||
def get_module_abbreviation(module_name, module_dict):
|
||||
|
||||
@@ -146,24 +146,12 @@ def get_agent_models(
|
||||
|
||||
|
||||
def report(
|
||||
mac_address: str, session_id: str, chat_type: int, content: str, opus_data
|
||||
mac_address: str, session_id: str, chat_type: int, content: str, audio
|
||||
) -> Optional[Dict]:
|
||||
"""带熔断的业务方法示例"""
|
||||
if not content or not ManageApiClient._instance:
|
||||
return None
|
||||
try:
|
||||
# 处理opus_data为列表的情况
|
||||
if isinstance(opus_data, list):
|
||||
# 将列表中的所有bytes数据合并
|
||||
combined_data = b"".join(opus_data)
|
||||
else:
|
||||
combined_data = opus_data
|
||||
|
||||
# 将二进制数据转换为Base64编码的字符串
|
||||
opus_data_base64 = (
|
||||
base64.b64encode(combined_data).decode("utf-8") if combined_data else None
|
||||
)
|
||||
|
||||
return ManageApiClient._instance._execute_request(
|
||||
"POST",
|
||||
f"/agent/chat-history/report",
|
||||
@@ -172,7 +160,9 @@ def report(
|
||||
"sessionId": session_id,
|
||||
"chatType": chat_type,
|
||||
"content": content,
|
||||
"opusDataBase64": opus_data_base64,
|
||||
"audioBase64": (
|
||||
base64.b64encode(audio).decode("utf-8") if audio else None
|
||||
),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
|
||||
@@ -9,6 +9,11 @@ TTS上报功能已集成到ConnectionHandler类中。
|
||||
具体实现请参考core/connection.py中的相关代码。
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import wave
|
||||
import opuslib_next
|
||||
|
||||
from config.logger import setup_logging
|
||||
from config.manage_api_client import report
|
||||
|
||||
@@ -26,18 +31,69 @@ def report_tts(conn, type, text, opus_data):
|
||||
opus_data: opus音频数据
|
||||
"""
|
||||
try:
|
||||
if opus_data:
|
||||
audio_data = opus_to_wav(opus_data)
|
||||
else:
|
||||
audio_data = None
|
||||
# 执行上报
|
||||
report(
|
||||
mac_address=conn.device_id,
|
||||
session_id=conn.session_id,
|
||||
chat_type=type,
|
||||
content=text,
|
||||
opus_data=opus_data,
|
||||
audio=audio_data,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.bind(tag=TAG).error(f"TTS上报失败: {e}")
|
||||
|
||||
|
||||
def opus_to_wav(opus_data):
|
||||
"""将Opus数据转换为WAV格式的字节流
|
||||
|
||||
Args:
|
||||
output_dir: 输出目录(保留参数以保持接口兼容)
|
||||
opus_data: opus音频数据
|
||||
|
||||
Returns:
|
||||
bytes: WAV格式的音频数据
|
||||
"""
|
||||
decoder = opuslib_next.Decoder(16000, 1) # 16kHz, 单声道
|
||||
pcm_data = []
|
||||
|
||||
for opus_packet in opus_data:
|
||||
try:
|
||||
pcm_frame = decoder.decode(opus_packet, 960) # 960 samples = 60ms
|
||||
pcm_data.append(pcm_frame)
|
||||
except opuslib_next.OpusError as e:
|
||||
logger.bind(tag=TAG).error(f"Opus解码错误: {e}", exc_info=True)
|
||||
|
||||
if not pcm_data:
|
||||
raise ValueError("没有有效的PCM数据")
|
||||
|
||||
# 创建WAV文件头
|
||||
pcm_data_bytes = b"".join(pcm_data)
|
||||
num_samples = len(pcm_data_bytes) // 2 # 16-bit samples
|
||||
|
||||
# WAV文件头
|
||||
wav_header = bytearray()
|
||||
wav_header.extend(b"RIFF") # ChunkID
|
||||
wav_header.extend((36 + len(pcm_data_bytes)).to_bytes(4, "little")) # ChunkSize
|
||||
wav_header.extend(b"WAVE") # Format
|
||||
wav_header.extend(b"fmt ") # Subchunk1ID
|
||||
wav_header.extend((16).to_bytes(4, "little")) # Subchunk1Size
|
||||
wav_header.extend((1).to_bytes(2, "little")) # AudioFormat (PCM)
|
||||
wav_header.extend((1).to_bytes(2, "little")) # NumChannels
|
||||
wav_header.extend((16000).to_bytes(4, "little")) # SampleRate
|
||||
wav_header.extend((32000).to_bytes(4, "little")) # ByteRate
|
||||
wav_header.extend((2).to_bytes(2, "little")) # BlockAlign
|
||||
wav_header.extend((16).to_bytes(2, "little")) # BitsPerSample
|
||||
wav_header.extend(b"data") # Subchunk2ID
|
||||
wav_header.extend(len(pcm_data_bytes).to_bytes(4, "little")) # Subchunk2Size
|
||||
|
||||
# 返回完整的WAV数据
|
||||
return bytes(wav_header) + pcm_data_bytes
|
||||
|
||||
|
||||
def enqueue_tts_report(conn, type, text, opus_data):
|
||||
if not conn.read_config_from_api:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user