import asyncio import sys from pathlib import Path if sys.platform.startswith("win"): asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse from .api.router import api_router from .core.config import get_settings def create_app() -> FastAPI: settings = get_settings() app = FastAPI(title=settings.app_name, version="0.1.0") app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(api_router, prefix=settings.api_prefix) static_root = Path(__file__).resolve().parents[2] / "frontend" / "dist" if static_root.exists(): index_file = static_root / "index.html" @app.get("/", include_in_schema=False) def serve_index() -> FileResponse: return FileResponse(index_file) @app.get("/{full_path:path}", include_in_schema=False) def serve_spa(full_path: str) -> FileResponse: if full_path.startswith("api/"): raise HTTPException(status_code=404) candidate = (static_root / full_path).resolve() if not str(candidate).startswith(str(static_root.resolve())): raise HTTPException(status_code=404) if candidate.is_file(): return FileResponse(candidate) return FileResponse(index_file) return app app = create_app()