import asyncio import logging import pathlib import sys from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse, JSONResponse, Response from backend.api.routes.analyze import router as analyze_router from backend.api.routes.crawl import router as crawl_router from backend.api.routes.deep_review import router as deep_review_router from backend.api.routes.projects import router as projects_router from backend.api.routes.reports import router as reports_router from backend.api.routes.screenshot import router as screenshot_router from backend.db.schema import init_db from backend.services import benchmark_service logging.basicConfig( stream=sys.stdout, level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", datefmt="%Y-%m-%dT%H:%M:%S", ) _log = logging.getLogger(__name__) _FRONTEND = pathlib.Path(__file__).resolve().parents[2] / "frontend" _DASHBOARD = _FRONTEND / "index.html" _GALLERY = _FRONTEND / "gallery.html" app = FastAPI( title="UICopilot", description="AI UI/UX Engineering Platform", version="0.1.0", ) app.include_router(analyze_router, prefix="/api/v1") app.include_router(screenshot_router, prefix="/api/v1") app.include_router(crawl_router, prefix="/api/v1") app.include_router(deep_review_router, prefix="/api/v1") app.include_router(reports_router, prefix="/api/v1") app.include_router(projects_router, prefix="/api/v1") @app.exception_handler(Exception) async def unhandled_exception(request: Request, exc: Exception) -> JSONResponse: _log.error("Unhandled error on %s %s: %s", request.method, request.url.path, exc, exc_info=True) return JSONResponse(status_code=500, content={"error": str(exc)}) @app.on_event("startup") async def startup() -> None: _log.info("UICopilot starting — DB_PATH=%s", pathlib.Path( __import__("os").environ.get("DB_PATH", "data/uicopilot.db") )) await init_db() loop = asyncio.get_event_loop() loop.run_in_executor(None, benchmark_service.prewarm) @app.get("/health") def health() -> dict[str, str]: return {"status": "ok"} @app.get("/", include_in_schema=False) def dashboard() -> Response: return Response( content=_DASHBOARD.read_text(encoding="utf-8"), media_type="text/html", headers={"Cache-Control": "no-store"}, ) @app.get("/gallery", response_class=HTMLResponse, include_in_schema=False) def gallery() -> str: return _GALLERY.read_text(encoding="utf-8")