Merge branch 'main' into tts-response

# Conflicts:
#	main/manager-web/.env.development
This commit is contained in:
hrz
2025-04-09 21:46:59 +08:00
129 changed files with 8298 additions and 2083 deletions
@@ -2,14 +2,16 @@
Opus编码工具类
将PCM音频数据编码为Opus格式
"""
import array
import logging
import traceback
import numpy as np
from typing import List, Optional
from opuslib import Encoder
from opuslib import constants
from opuslib_next import Encoder
from opuslib_next import constants
class OpusEncoderUtils:
"""PCM到Opus的编码器"""
@@ -17,7 +19,7 @@ class OpusEncoderUtils:
def __init__(self, sample_rate: int, channels: int, frame_size_ms: int):
"""
初始化Opus编码器
Args:
sample_rate: 采样率 (Hz)
channels: 通道数 (1=单声道, 2=立体声)
@@ -30,20 +32,18 @@ class OpusEncoderUtils:
self.frame_size = (sample_rate * frame_size_ms) // 1000
# 总帧大小 = 每帧样本数 * 通道数
self.total_frame_size = self.frame_size * channels
# 比特率和复杂度设置
self.bitrate = 24000 # bps
self.complexity = 10 # 最高质量
# 缓冲区初始化为空
self.buffer = np.array([], dtype=np.int16)
try:
# 创建Opus编码器
self.encoder = Encoder(
sample_rate,
channels,
constants.APPLICATION_AUDIO # 音频优化模式
sample_rate, channels, constants.APPLICATION_AUDIO # 音频优化模式
)
self.encoder.bitrate = self.bitrate
self.encoder.complexity = self.complexity
@@ -60,48 +60,48 @@ class OpusEncoderUtils:
def encode_pcm_to_opus(self, pcm_data: bytes, end_of_stream: bool) -> List[bytes]:
"""
将PCM数据编码为Opus格式
Args:
pcm_data: PCM字节数据
end_of_stream: 是否为流的结束
Returns:
Opus数据包列表
"""
# 将字节数据转换为short数组
new_samples = self._convert_bytes_to_shorts(pcm_data)
# 校验PCM数据
self._validate_pcm_data(new_samples)
# 将新数据追加到缓冲区
self.buffer = np.append(self.buffer, new_samples)
opus_packets = []
offset = 0
# 处理所有完整帧
while offset <= len(self.buffer) - self.total_frame_size:
frame = self.buffer[offset:offset + self.total_frame_size]
frame = self.buffer[offset : offset + self.total_frame_size]
output = self._encode(frame)
if output:
opus_packets.append(output)
offset += self.total_frame_size
# 保留未处理的样本
self.buffer = self.buffer[offset:]
# 流结束时处理剩余数据
if end_of_stream and len(self.buffer) > 0:
# 创建最后一帧并用0填充
last_frame = np.zeros(self.total_frame_size, dtype=np.int16)
last_frame[:len(self.buffer)] = self.buffer
last_frame[: len(self.buffer)] = self.buffer
output = self._encode(last_frame)
if output:
opus_packets.append(output)
self.buffer = np.array([], dtype=np.int16)
return opus_packets
def _encode(self, frame: np.ndarray) -> Optional[bytes]:
@@ -134,4 +134,4 @@ class OpusEncoderUtils:
def close(self):
"""关闭编码器并释放资源"""
# opuslib没有明确的关闭方法,Python的垃圾回收会处理
pass
pass