CityTrack / Backend /api /app.py
vxrachit's picture
Setup Supabase Auth and Fastapi middleware.
9d6129a
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from Backend.core.config import settings
from Backend.core.events import event_bus
from Backend.core.logging import setup_logging, get_logger
from Backend.core.security import SecurityHeadersMiddleware, RateLimitMiddleware, RequestValidationMiddleware
from Backend.database.connection import init_db, close_db
from Backend.api.routes import api_router
logger = get_logger(__name__)
STATIC_DIR = Path("static")
@asynccontextmanager
async def lifespan(app: FastAPI):
setup_logging(debug=settings.debug)
logger.info("Starting City Issue Resolution Agent")
await init_db()
logger.info("Database initialized")
await event_bus.start()
logger.info("Event bus started")
from Backend.agents.vision import VisionAgent
try:
VisionAgent.load_model()
logger.info("Vision model loaded")
except Exception as e:
logger.warning(f"Vision model failed to load: {e}. Running in mock mode.")
import asyncio
from Backend.database.connection import get_db_context
from Backend.agents.escalation.agent import EscalationAgent
from Backend.agents.sla.agent import SLAAgent
async def run_periodic_checks():
while True:
try:
logger.info("Running periodic SLA and Escalation checks...")
async with get_db_context() as db:
esc_agent = EscalationAgent(db)
await esc_agent.check_all_pending()
sla_agent = SLAAgent(db)
await sla_agent.check_all_active()
except Exception as e:
logger.error(f"Error in background task: {e}")
await asyncio.sleep(900)
task = asyncio.create_task(run_periodic_checks())
yield
task.cancel()
await event_bus.stop()
await close_db()
logger.info("Shutdown complete")
def create_app() -> FastAPI:
app = FastAPI(
title="City Issue Resolution Agent",
description="Autonomous urban issue detection and resolution platform",
version="1.0.0",
lifespan=lifespan,
root_path="",
)
# CORS must be added first
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
)
app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(RateLimitMiddleware, requests_per_minute=120, burst_limit=20)
app.add_middleware(RequestValidationMiddleware)
settings.local_temp_dir.mkdir(parents=True, exist_ok=True)
STATIC_DIR.mkdir(parents=True, exist_ok=True)
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
app.include_router(api_router)
@app.get("/")
async def root():
return FileResponse(STATIC_DIR / "flow.html")
@app.get("/dashboard")
async def dashboard():
return FileResponse(STATIC_DIR / "flow.html")
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
return JSONResponse(
status_code=400,
content={"detail": str(exc)}
)
@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
logger.error(f"Unhandled exception: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={"detail": "Internal server error"}
)
return app