live-wizard/services/router/server.py
2026-07-08 19:27:17 +00:00

69 lines
1.9 KiB
Python

"""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)