OptiQ / api /main.py
mohammademad2003's picture
first commit
7477316
"""
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,
)