FlagshipAi / server.py
Ali2206's picture
Fix AIAutomation router conflict and remove manual invoice route
c8ee813
import os
import sys
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from dotenv import load_dotenv, find_dotenv
# Ensure project root on sys.path for package imports
ROOT_DIR = Path(__file__).resolve().parent
if str(ROOT_DIR) not in sys.path:
sys.path.append(str(ROOT_DIR))
# Load environment (HF Spaces will inject secrets via env vars)
load_dotenv(find_dotenv(), override=True)
app = FastAPI(title="Flagship AI", version="0.1.0")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- Static assets (shared Suite styles/header) ---
SUITE_STATIC_DIR = (ROOT_DIR / "Suite" / "app" / "static").resolve()
app.mount("/static", StaticFiles(directory=str(SUITE_STATIC_DIR)), name="static")
# --- Include routers from agents that already use prefixed routes ---
# UX Prototyper uses router prefix '/ux'
try:
from AIDesign.app.main import router as ux_router # type: ignore
app.include_router(ux_router)
except Exception:
# Optional: keep the app booting even if module missing
pass
# Slack Knowledge Bot uses router prefix '/slack'
try:
from AIIntegration.app.main import router as slack_router # type: ignore
app.include_router(slack_router)
except Exception:
pass
# AI Readiness Audit uses router prefix '/audit'
try:
print("Attempting to import AIReadiness...")
from AIReadiness.app.main import router as audit_router # type: ignore
print(f"Successfully imported AIReadiness router: {audit_router}")
print(f"Router prefix: {audit_router.prefix}")
app.include_router(audit_router)
print("Successfully included AIReadiness router")
except Exception as e:
print(f"Failed to import AIReadiness router: {e}")
import traceback
traceback.print_exc()
pass
# Additional prefixed routers
for mod_path, name in (
("AIAccessibility.app.main", "access_router"),
("AIAutomation.app.main", "automation_router"),
("AIStrategy.app.main", "strategy_router"),
("AIFit.app.main", "fit_router"),
("AIDual.app.main", "dual_router"),
("AIQuiz.app.main", "quiz_router"),
("AIRoute.app.main", "route_router"),
("AISaas.app.main", "saas_router"),
):
try:
print(f"Importing {mod_path}...")
module = __import__(mod_path, fromlist=["router"]) # type: ignore
router = getattr(module, "router")
print(f"Successfully imported {name}: {router}")
print(f"Router routes: {[route.path for route in router.routes]}")
app.include_router(router) # type: ignore
print(f"Successfully included {name}")
except Exception as e:
print(f"Failed to import {mod_path}: {e}")
import traceback
traceback.print_exc()
pass
# --- Mount full apps where clean scoping is needed ---
# Opportunity Planner (AISolutions) has unprefixed routes; mount under '/solutions'
try:
from AISolutions.app.main import app as solutions_app # type: ignore
app.mount("/solutions", solutions_app)
except Exception:
pass
# Include routers with proper prefixes
try:
from AIArchitecture.app.main import router as arch_router # type: ignore
app.include_router(arch_router)
except Exception:
pass
try:
from AICommerce.app.main import router as commerce_router # type: ignore
app.include_router(commerce_router)
except Exception:
pass
# AIAutomation is now included in the loop above
try:
from AIHealthcare.app.main import router as healthcare_router # type: ignore
app.include_router(healthcare_router)
except Exception:
pass
# These routers are already included by the loop above
# --- Index routes for top-level and agent landings ---
@app.get("/")
def suite_index() -> FileResponse:
"""Serve the Flagship Suite landing page."""
return FileResponse((SUITE_STATIC_DIR / "index.html").as_posix())
@app.get("/ux")
def ux_index() -> FileResponse:
base = ROOT_DIR / "AIDesign" / "app" / "static" / "index.html"
return FileResponse(base.as_posix())
@app.get("/slack")
def slack_index() -> FileResponse:
base = ROOT_DIR / "AIIntegration" / "app" / "static" / "index.html"
return FileResponse(base.as_posix())
# Audit route is now handled by the AIReadiness router
# Static index shortcuts for mounted apps and prefixed routers
@app.get("/solutions/")
def solutions_index_redirect() -> RedirectResponse:
# Mounted app handles this; ensure trailing slash variant resolves
return RedirectResponse(url="/solutions/")
# These routes are now handled by their respective routers
@app.get("/triage")
def triage_index() -> FileResponse:
base = ROOT_DIR / "AIHealthcare" / "app" / "static" / "index.html"
return FileResponse(base.as_posix())
# Invoice route is now handled by the AIAutomation router
# These routes are now handled by their respective routers
# Optional health endpoint for the aggregator
@app.get("/healthz")
def healthz() -> dict:
return {
"status": "ok",
"openai_key": bool(os.getenv("OPENAI_API_KEY")),
"version": "0.1.0",
}