ASR-demo/scripts/run_frontend.py

58 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""Serve the browser UI independently of the FunASR backend."""
from __future__ import annotations
import json
import os
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import urlsplit
from dotenv import load_dotenv
PROJECT_ROOT = Path(__file__).resolve().parents[1]
STATIC_ROOT = PROJECT_ROOT / "realtime_websocket" / "static"
load_dotenv(PROJECT_ROOT / ".env")
class FrontendHandler(SimpleHTTPRequestHandler):
"""Serve static assets and a browser-visible backend URL at runtime."""
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=str(STATIC_ROOT), **kwargs)
def do_GET(self) -> None:
if self.path.split("?", 1)[0] != "/runtime-config.js":
return super().do_GET()
backend_url = os.getenv("BACKEND_PUBLIC_URL", "http://127.0.0.1:8082").rstrip("/")
parsed = urlsplit(backend_url)
if parsed.scheme not in {"http", "https"} or not parsed.netloc or parsed.path:
self.send_error(500, "BACKEND_PUBLIC_URL must be an HTTP origin")
return
# JSON escaping also yields a valid JavaScript string literal.
body = ("window.ASR_BACKEND_URL = " + json.dumps(backend_url) + ";\n").encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/javascript; charset=utf-8")
self.send_header("Cache-Control", "no-store")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def main() -> None:
host = os.getenv("FRONTEND_HOST", "127.0.0.1")
port = int(os.getenv("FRONTEND_PORT", "8080"))
server = ThreadingHTTPServer((host, port), FrontendHandler)
print(f"Frontend: http://{host}:{port}/", flush=True)
try:
server.serve_forever()
except KeyboardInterrupt:
pass
finally:
server.server_close()
if __name__ == "__main__":
main()