Merge branch 'main' into py-display

This commit is contained in:
CGD
2026-03-31 14:24:27 +08:00
committed by GitHub
74 changed files with 1034 additions and 451 deletions
+2 -2
View File
@@ -751,8 +751,8 @@ class ConnectionHandler:
memory_type = self.config["Memory"][self.config["selected_module"]["Memory"]][
"type"
]
# 如果使用 nomen,直接返回
if memory_type == "nomem":
# 如果使用 nomen 或 mem_report_only,直接返回
if memory_type == "nomem" or memory_type == "mem_report_only":
return
# 使用 mem_local_short 模式
elif memory_type == "mem_local_short":
@@ -280,6 +280,8 @@ async def send_tts_message(conn: "ConnectionHandler", state, text=None):
await sendAudio(conn, audios)
# 等待所有音频包发送完成
await _wait_for_audio_completion(conn)
# 停止音频发送循环
conn.audio_rate_controller.stop_sending()
# 清除服务端讲话状态
conn.clearSpeakStatus()
@@ -0,0 +1,20 @@
"""
仅上报聊天记录,不进行记忆总结
"""
from ..base import MemoryProviderBase, logger
TAG = __name__
class MemoryProvider(MemoryProviderBase):
def __init__(self, config, summary_memory=None):
super().__init__(config)
async def save_memory(self, msgs, session_id=None):
logger.bind(tag=TAG).debug("mem_report_only mode: No memory saving or summarization is performed.")
return None
async def query_memory(self, query: str) -> str:
logger.bind(tag=TAG).debug("mem_report_only mode: No memory query is performed.")
return ""
@@ -27,6 +27,7 @@ class AudioRateController:
self.queue_empty_event = asyncio.Event() # 队列清空事件
self.queue_empty_event.set() # 初始为空状态
self.queue_has_data_event = asyncio.Event() # 队列数据事件
self._last_queue_empty_time = 0 # 上次队列清空的时间(秒)
def reset(self):
"""重置控制器状态"""
@@ -37,12 +38,25 @@ class AudioRateController:
self.queue.clear()
self.play_position = 0
self.start_timestamp = None # 由首个音频包设置
self._last_queue_empty_time = 0 # 重置时间
# 相关事件处理
self.queue_empty_event.set()
self.queue_has_data_event.clear()
def add_audio(self, opus_packet):
"""添加音频包到队列"""
# 如果队列之前为空,需要调整时间戳以保持播放时间连续
# 这样工具调用等待期间,新加入的音频不会提前播放
# 如果间隔很短(<1帧),说明是正常的流式传输,不需要重置
if len(self.queue) == 0 and self.play_position > 0:
elapsed_since_empty = (time.monotonic() - self._last_queue_empty_time) * 1000
# 只有间隔超过1帧时长,才认为是真正的"暂停恢复"
if elapsed_since_empty >= self.frame_duration:
self.start_timestamp = time.monotonic() - (self.play_position / 1000)
self.logger.bind(tag=TAG).debug(
f"队列从空恢复,重置时间戳,当前播放位置: {self.play_position}ms,间隔: {elapsed_since_empty:.0f}ms"
)
self.queue.append(("audio", opus_packet))
# 相关事件处理
self.queue_empty_event.clear()
@@ -55,6 +69,14 @@ class AudioRateController:
Args:
message_callback: 消息发送回调函数 async def()
"""
if len(self.queue) == 0 and self.play_position > 0:
elapsed_since_empty = (time.monotonic() - self._last_queue_empty_time) * 1000
if elapsed_since_empty >= self.frame_duration:
self.start_timestamp = time.monotonic() - (self.play_position / 1000)
self.logger.bind(tag=TAG).debug(
f"队列从空恢复,重置时间戳,当前播放位置: {self.play_position}ms,间隔: {elapsed_since_empty:.0f}ms"
)
self.queue.append(("message", message_callback))
# 相关事件处理
self.queue_empty_event.clear()
@@ -126,6 +148,7 @@ class AudioRateController:
# 队列处理完后清除事件
self.queue_empty_event.set()
self.queue_has_data_event.clear()
self._last_queue_empty_time = time.monotonic() # 记录队列清空时间
def start_sending(self, send_audio_callback):
"""
+1 -1
View File
@@ -26,7 +26,7 @@ mem0ai==1.0.0
powermem>=0.3.1
bs4==0.0.2
modelscope==1.32.0
sherpa_onnx==1.12.17
sherpa_onnx==1.12.29
mcp==1.22.0
cnlunar==0.2.0
PySocks==1.7.1
+2 -2
View File
@@ -192,7 +192,7 @@ class App {
}
log('正在请求摄像头权限...', 'info');
this.cameraStream = await navigator.mediaDevices.getUserMedia({
video: { width: 320, height: 240, facingMode: this.currentFacingMode },
video: { width: 180, height: 240, facingMode: this.currentFacingMode },
audio: false
});
cameraVideo.srcObject = this.cameraStream;
@@ -274,7 +274,7 @@ class App {
return;
}
canvas.width = video.videoWidth || 320;
canvas.width = video.videoWidth || 180;
canvas.height = video.videoHeight || 240;
const ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);