#!/usr/bin/env python3 """ Patch speaker.py in-place to be headless-safe. Replaces the sd.OutputStream block with a dummy loop that just sends READY. """ import os SPEAKER_PATH = "/opt/qwen3-tts/qwen3_tts_gguf/inference/workers/speaker.py" with open(SPEAKER_PATH, "r") as f: content = f.read() # Replace the try block at the end of speaker_worker_proc old = ''' try: with sd.OutputStream(samplerate=sample_rate, channels=1, callback=audio_callback, blocksize=2048): # 握手 if result_queue: result_queue.put(SpeakerResponse(msg_type="READY")) while True: time.sleep(0.2) if state.get("stop"): break except KeyboardInterrupt: pass except Exception as e: print(f"❌ [SpeakerWorker] 异常: {e}")''' new = ''' try: with sd.OutputStream(samplerate=sample_rate, channels=1, callback=audio_callback, blocksize=2048): # 握手 if result_queue: result_queue.put(SpeakerResponse(msg_type="READY")) while True: time.sleep(0.2) if state.get("stop"): break except KeyboardInterrupt: pass except Exception as e: print(f"⚠️ [SpeakerWorker] No audio device, running headless: {e}") # Headless fallback: send READY and drain queue without playback if result_queue: result_queue.put(SpeakerResponse(msg_type="READY")) while not state.get("stop"): try: command = play_queue.get(timeout=0.5) handle_command(command, state) except Exception: pass''' if old in content: content = content.replace(old, new) with open(SPEAKER_PATH, "w") as f: f.write(content) print("OK: speaker.py patched with headless fallback") else: print("WARNING: exact match not found, trying simplified patch...") # Try to find and patch just the except Exception block if '❌ [SpeakerWorker] 异常' in content: content = content.replace( 'print(f"❌ [SpeakerWorker] 异常: {e}")', '''print(f"⚠️ [SpeakerWorker] No audio device, running headless: {e}") # Headless fallback: send READY and drain queue without playback if result_queue: result_queue.put(SpeakerResponse(msg_type="READY")) while not state.get("stop"): try: command = play_queue.get(timeout=0.5) handle_command(command, state) except Exception: pass''' ) with open(SPEAKER_PATH, "w") as f: f.write(content) print("OK: speaker.py patched (simplified)") else: print("ERROR: Could not find patch target in speaker.py")