| 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="", |
| ) |
| |
| |
| 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 |
|
|