"""Router: mic/WebSocket -> brain -> TTS -> avatar -> RTMP streaming glue.""" import os, json, queue, threading, time from pathlib import Path from flask import Flask, request, jsonify from flask_sock import Sock import requests app = Flask(__name__) sock = Sock(app) BRAIN = os.getenv("BRAIN_URL", "http://brain:11434") TTS = os.getenv("TTS_URL", "http://tts:5002") PERSONA = os.getenv("PERSONA", "/app/persona.yaml") response_q = queue.Queue() def build_prompt(user_text): return user_text def brain_reply(prompt): try: r = requests.post(f"{BRAIN}/api/generate", json={"model":"llama3.2:1b","prompt":prompt,"stream":False}, timeout=20) return r.json().get("response","") except Exception as e: return f"*static from the aether* {e}" def tts_synth(text): try: r = requests.post(f"{TTS}/synthesize", json={"text": text}, timeout=20) return r.content except Exception: return b"" def run_job(text): prompt = build_prompt(text) reply = brain_reply(prompt) audio = tts_synth(reply) response_q.put({"text": reply, "audio": audio}) @app.post("/say") def say(): data = request.get_json(force=True) text = data.get("text", "") if not text: return jsonify({"error": "text required"}), 400 threading.Thread(target=run_job, args=(text,), daemon=True).start() return jsonify({"queued": True}) @app.get("/health") def health(): return {"status": "ok", "queued": response_q.qsize()} @sock.route("/ws") def ws(ws): while True: msg = ws.receive() if msg is None: break try: data = json.loads(msg) except Exception: continue if data.get("type") == "text": run_job(data.get("text","")) result = response_q.get() ws.send(json.dumps(result)) if __name__ == "__main__": app.run(host="0.0.0.0", port=8787)