import io import wave import requests import soundfile as sf import numpy as np import subprocess import sys GATEWAY_URL = "http://localhost:8003" CHAT_ENDPOINT = f"{GATEWAY_URL}/api/chat" # feste Annahmen für Gemini 3.1 Flash TTS über OpenRouter SAMPLE_RATE = 24000 CHANNELS = 1 SAMPLE_WIDTH = 2 # 16-bit PCM def pcm_to_wav(pcm_bytes: bytes, wav_path: str) -> None: """Rohes s16le-PCM in eine WAV-Datei schreiben.""" with wave.open(wav_path, "wb") as wf: wf.setnchannels(CHANNELS) wf.setsampwidth(SAMPLE_WIDTH) wf.setframerate(SAMPLE_RATE) wf.writeframes(pcm_bytes) def play_wav(wav_path: str) -> None: """WAV-Datei abspielen (ffplay oder aplay/mpv, je nach System).""" for cmd in ( ["ffplay", "-nodisp", "-autoexit", wav_path], ["aplay", wav_path], ["mpv", wav_path], ): try: subprocess.run(cmd, check=True) return except (FileNotFoundError, subprocess.CalledProcessError): continue print(f"Konnte keine geeignete Player-CLI finden für {wav_path}", file=sys.stderr) def chat_and_play(text: str, language: str = "de") -> None: payload = {"text": text, "language": language} resp = requests.post( CHAT_ENDPOINT, json=payload, stream=True, ) if not resp.ok: print("HTTP", resp.status_code) print(resp.text) return pcm_bytes = b"".join(resp.iter_content(chunk_size=8192)) # Hinweis: Den Text-Trace (Transkript/Antwort) liefert /api/chat nur im JSON, # wenn man ?debug=true anhängt - nicht als Header im Audio-Stream. print("Audio-Format:", resp.headers.get("X-Audio-Format")) print("Sample-Rate:", resp.headers.get("X-Audio-Sample-Rate")) wav_path = "chat_reply.wav" pcm_to_wav(pcm_bytes, wav_path) print(f"WAV gespeichert unter {wav_path}") play_wav(wav_path) if __name__ == "__main__": if len(sys.argv) > 1: user_text = " ".join(sys.argv[1:]) else: user_text = "Wie wird das Wetter morgen in Bünde?" chat_and_play(user_text, language="de")