From 346a8076e6bc1bca0e2e7b26eaeed62a105264cc Mon Sep 17 00:00:00 2001 From: RichardToo <26624752+RichardToo@users.noreply.github.com> Date: Thu, 15 Oct 2026 21:55:21 +0900 Subject: [PATCH] fix(realtime): don't kill the listen loop on receive() timeout simple_websocket's receive(timeout=1) returns None when no frame arrives in time; it does NOT mean the connection closed. The recv_loop treated None as a disconnect, so any client that pauses sending for >1s (i.e. any silence longer than one second, or a mic that only transmits while speaking) permanently stopped the session from hearing the user -- barge-in and the next turn both went dead while generation kept streaming out. Also default --device to MPS when CUDA is unavailable, so CPU-only Mac paths stop falling back to cpu. --- eval_omni.py | 2 +- webui/web_demo.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/eval_omni.py b/eval_omni.py index e12d6f9..7410584 100644 --- a/eval_omni.py +++ b/eval_omni.py @@ -99,7 +99,7 @@ def main(): parser.add_argument('--temperature', default=0.7, type=float, help="Thinker生成温度") parser.add_argument('--top_p', default=0.85, type=float, help="nucleus采样阈值") parser.add_argument('--output_dir', default='./output_audio/', type=str, help="输出音频保存目录") - parser.add_argument('--device', default='cuda' if torch.cuda.is_available() else 'cpu', type=str, help="运行设备") + parser.add_argument('--device', default='cuda' if torch.cuda.is_available() else ('mps' if torch.backends.mps.is_available() else 'cpu'), type=str, help="运行设备") parser.add_argument('--audio_dir', default='./dataset/eval_omni/', type=str, help="测试音频目录") parser.add_argument('--image_dir', default='./dataset/eval_omni/', type=str, help="测试图像目录") parser.add_argument('--open_thinking', default=0, type=int, help="是否开启思考模式(0=否,1=是)(思考模式下禁用audio输出)") diff --git a/webui/web_demo.py b/webui/web_demo.py index 3702fc0..e9a0d7d 100644 --- a/webui/web_demo.py +++ b/webui/web_demo.py @@ -383,9 +383,12 @@ def realtime(ws): while alive[0]: try: data = ws.receive(timeout=1) - if data is None: alive[0] = False; break + except Exception: + alive[0] = False; break # 只有真断开/异常才退出 + # flask_sock 超时返回 None,并不表示连接关闭:客户端只要暂停送帧 >1s + # (例如助手说话期间没人出声),旧写法会在这里误判断线并永久停止监听。 + if data is not None: q.put(data) - except: alive[0] = False; break threading.Thread(target=recv_loop, daemon=True).start() try: @@ -493,7 +496,7 @@ def init_model(args): if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--load_from', default='./', help='模型权重搜索目录;目录下可放多个 HF 格式模型,WebUI 会自动扫描并允许切换。') - p.add_argument('--device', default='cuda' if torch.cuda.is_available() else 'cpu', help='推理设备;CUDA 可用时默认 cuda。显存不足或排查环境问题时可改为 cpu。') + p.add_argument('--device', default='cuda' if torch.cuda.is_available() else ('mps' if torch.backends.mps.is_available() else 'cpu'), help='推理设备;优先 CUDA,其次 Apple Silicon 的 MPS,否则 CPU。') p.add_argument('--port', default=7860, type=int, help='WebUI 服务端口;端口被占用或需要同时启动多个实例时调整。') p.add_argument('--audio_chunk_frames', default=4, type=int, help='流式播放每次解码的 Mimi frame 数;默认 4 约 320ms。WebUI 播放卡顿时可调大到 8/12,低延迟优先时保持 4。') p.add_argument('--audio_overlap', default=2, type=int, help='分块 Mimi 解码的重叠帧数;默认 2 用于缓解块边界断裂。一般不需要调整,边界杂音明显时可适当增大。')