""" OptiQ API — FastAPI entry point. Serves the hybrid Quantum-AI-Classical optimization pipeline. Extended for SaaS platform with authentication, analytics, and reporting. """ from __future__ import annotations import sys import os # Ensure project root is on the path so ``from src.*`` and ``from config`` work. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # Load .env file if present try: from dotenv import load_dotenv load_dotenv(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")) except ImportError: pass from pathlib import Path from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from config import CFG # Initialize database on startup from api.database import init_db init_db() # Import routers from api.routes.baseline import router as baseline_router from api.routes.optimize import router as optimize_router from api.routes.compare import router as compare_router from api.routes.validate import router as validate_router from api.routes.grid import router as grid_router from api.routes.simulate import router as simulate_router from api.routes.digital_twin import router as digital_twin_router from api.routes.usage import router as usage_router from api.routes.audit import router as audit_router from api.routes.roi import router as roi_router from api.routes.report import router as report_router from api.routes.auth_routes import router as auth_router app = FastAPI( title="OptiQ SaaS API", description=( "AI-Powered Distribution Grid Reconfiguration Platform. " "Hybrid Quantum-AI-Classical optimization for power distribution networks. " "Reduces grid losses by 30%+ through intelligent network reconfiguration." ), version="1.0.0", ) # CORS — allow the frontend (and any origin during dev) app.add_middleware( CORSMiddleware, allow_origins=CFG.api.cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Register routers app.include_router(baseline_router, prefix="/api", tags=["Baseline"]) app.include_router(optimize_router, prefix="/api", tags=["Optimize"]) app.include_router(compare_router, prefix="/api", tags=["Compare"]) app.include_router(validate_router, prefix="/api", tags=["Validate"]) app.include_router(grid_router, prefix="/api", tags=["Grid"]) app.include_router(simulate_router, prefix="/api", tags=["Simulate"]) app.include_router(digital_twin_router, prefix="/api", tags=["Digital Twin"]) app.include_router(usage_router, prefix="/api", tags=["Usage"]) app.include_router(audit_router, prefix="/api", tags=["Audit"]) app.include_router(roi_router, prefix="/api", tags=["ROI"]) app.include_router(report_router, prefix="/api", tags=["Report"]) app.include_router(auth_router, prefix="/api", tags=["Auth"]) @app.get("/api/health", tags=["Health"]) def health(): return {"status": "ok", "project": "OptiQ", "version": "1.0.0"} # ── Serve React frontend from /frontend/dist ───────────────────────────── _PROJECT_ROOT = Path(__file__).resolve().parent.parent _FRONTEND_DIST = _PROJECT_ROOT / "frontend" / "dist" if _FRONTEND_DIST.is_dir(): # Serve static assets (JS, CSS, images, etc.) app.mount("/assets", StaticFiles(directory=_FRONTEND_DIST / "assets"), name="assets") # Catch-all: serve index.html for any non-API route (SPA client-side routing) @app.get("/{full_path:path}", include_in_schema=False) async def serve_spa(request: Request, full_path: str): # If a static file exists at the path, serve it directly file_path = _FRONTEND_DIST / full_path if full_path and file_path.is_file(): return FileResponse(file_path) # Otherwise serve index.html for client-side routing return FileResponse(_FRONTEND_DIST / "index.html") else: @app.get("/", include_in_schema=False) def root_no_frontend(): return {"message": "OptiQ API running. Build frontend with: cd frontend && npm run build"} if __name__ == "__main__": import uvicorn uvicorn.run( "api.main:app", host=CFG.api.host, port=CFG.api.port, reload=CFG.api.reload, )