Files
BSN-Chatsystem/voice-chat/server.py
T

119 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""Basti Voice Chat Server — serves the web UI and proxies to Hermes API."""
import http.server
import json
import os
import sys
import urllib.request
import urllib.error
import uuid
import socketserver
from pathlib import Path
from urllib.parse import urlparse, parse_qs
PORT = int(os.environ.get("VOICE_CHAT_PORT", "8891"))
API_PORT = 8642
API_KEY = "866c20bd9c34d92bd34f1bf21cff6f52c40840da8ec6c562afac22dfc3f9ac8e"
STATIC_DIR = Path(__file__).parent
# Session history (in-memory, simple)
sessions = {}
class VoiceChatHandler(http.server.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=str(STATIC_DIR), **kwargs)
def do_POST(self):
if self.path == "/api/chat":
self.handle_chat()
elif self.path == "/api/chat/save":
self.handle_save()
else:
self.send_error(404)
def handle_chat(self):
content_len = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_len)
try:
data = json.loads(body)
user_text = data.get("text", "").strip()
except:
self.send_error(400, "Invalid JSON")
return
if not user_text:
self.send_error(400, "Missing 'text' field")
return
# Forward to Hermes API server
api_url = f"http://localhost:{API_PORT}/v1/chat/completions"
api_body = json.dumps({
"model": "hermes",
"messages": [
{"role": "system", "content": "Du bist Basti, Chef vom Dienst der digitalen Redaktion von brettspiel-news.de. Antworte auf Deutsch, freundlich und hilfreich. Halte deine Antworten kurz — maximal 3-4 Sätze. Dein Chef Daniel spricht mit dir."},
{"role": "user", "content": user_text}
],
"max_tokens": 300,
"temperature": 0.7
}).encode("utf-8")
req = urllib.request.Request(api_url, data=api_body, headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
})
try:
with urllib.request.urlopen(req, timeout=45) as resp:
result = json.loads(resp.read().decode())
reply = result.get("choices", [{}])[0].get("message", {}).get("content", "")
if not reply:
reply = "Hmm, da kam nichts zurück. Versuch's nochmal?"
except urllib.error.HTTPError as e:
err_body = e.read().decode() if e.fp else str(e)
reply = f"API-Fehler {e.code}: {err_body[:200]}"
except Exception as e:
reply = f"Server-Fehler: {str(e)[:200]}"
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.end_headers()
self.wfile.write(json.dumps({"response": reply}).encode())
def handle_save(self):
"""Save message pair for session continuity."""
content_len = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_len)
try:
data = json.loads(body)
except:
self.send_error(400)
return
# Simple append to history (not used by API currently)
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(json.dumps({"ok": True}).encode())
def do_OPTIONS(self):
self.send_response(200)
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "POST, OPTIONS")
self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.end_headers()
def log_message(self, format, *args):
# Quiet logging
pass
if __name__ == "__main__":
with socketserver.TCPServer(("0.0.0.0", PORT), VoiceChatHandler) as httpd:
print(f"🎤 Basti Voice Chat running on http://0.0.0.0:{PORT}")
print(f" External: http://185.162.249.159:{PORT}")
sys.stdout.flush()
httpd.serve_forever()