File size: 4,372 Bytes
55e3496
 
 
7477316
55e3496
 
 
 
 
 
 
 
 
7477316
 
 
 
 
 
 
 
 
 
55e3496
7477316
 
55e3496
 
7477316
 
 
 
 
 
55e3496
 
 
 
7477316
 
 
 
 
 
 
 
55e3496
 
7477316
55e3496
7477316
 
 
55e3496
7477316
55e3496
 
7477316
55e3496
 
 
 
 
 
 
 
 
 
 
 
 
7477316
 
 
 
 
 
 
 
55e3496
 
7477316
55e3496
7477316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55e3496
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
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,
    )