""" Local dev server — Windows-safe SelectorEventLoop runner. Use this instead of `uvicorn main:app` on Windows. It guarantees SelectorEventLoop, which psycopg_async requires (ProactorEventLoop, the Windows default, fails with psycopg3). reload=False is intentional — reload spawns subprocesses that lose the loop. Reads host and port from APP_BASE_URL in .env (e.g. http://192.168.1.36:7880). Reads log level from LOG_LEVEL in .env. Usage: uv run python dev_server.py Note: main.py is the FastAPI app entry point — used by uvicorn directly and by HF Spaces. This script is only needed for local Windows development. """ import asyncio import os import selectors import sys from urllib.parse import urlparse from dotenv import load_dotenv load_dotenv() import uvicorn def _host_port_from_base_url(url: str) -> tuple[str, int]: parsed = urlparse(url) host = parsed.hostname or "127.0.0.1" port = parsed.port or 8000 return host, port HOST, PORT = _host_port_from_base_url(os.getenv("APP_BASE_URL", "http://127.0.0.1:8000")) LOG_LEVEL = os.getenv("LOG_LEVEL", "info").lower() async def _serve(): config = uvicorn.Config("main:app", host=HOST, port=PORT, log_level=LOG_LEVEL) server = uvicorn.Server(config) await server.serve() if __name__ == "__main__": try: if sys.platform == "win32": # loop_factory requires Python 3.12+ — we're on 3.13, safe. asyncio.run( _serve(), loop_factory=lambda: asyncio.SelectorEventLoop(selectors.SelectSelector()), ) else: asyncio.run(_serve()) except KeyboardInterrupt: pass # Ctrl+C — server already shut down cleanly via uvicorn's signal handler