import time from typing import Callable from fastapi import FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware from starlette.middleware.base import BaseHTTPMiddleware from backend.core.config import settings from backend.core.exceptions import global_exception_handler from backend.core.logging import logger from backend.crud.request_log import create_request_log from backend.data.init_db import init_database from backend.data.mongodb_client import close_mongodb_connection from backend.routes.chat import router as chat_router from backend.routes.checkpoints import router as checkpoints_router from backend.routes.health import router as health_router from backend.routes.papers import router as papers_router from backend.routes.upload import router as upload_router class RequestLoggingMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next: Callable) -> Response: start_time = time.time() endpoint = request.url.path status_code = 200 error_type = None try: response = await call_next(request) status_code = response.status_code return response except Exception as exc: status_code = 500 error_type = type(exc).__name__ raise finally: response_time = time.time() - start_time if endpoint.startswith("/api/"): try: await create_request_log( response_time=response_time, endpoint=endpoint, status_code=status_code, error_type=error_type, ) except Exception as exc: logger.error(f"Failed to log request to MongoDB: {exc}") app = FastAPI( title=settings.APP_NAME, version=settings.API_VERSION, debug=settings.APP_DEBUG, ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.add_middleware(RequestLoggingMiddleware) app.include_router(health_router) app.include_router(chat_router) app.include_router(upload_router) app.include_router(papers_router) app.include_router(checkpoints_router) app.add_exception_handler(Exception, global_exception_handler) @app.on_event("startup") async def startup_event(): logger.info(f"Starting {settings.APP_NAME}...") success = await init_database() if not success: logger.error("Database initialisation failed — continuing without MongoDB") @app.on_event("shutdown") async def shutdown_event(): logger.info("Shutting down...") await close_mongodb_connection() @app.get("/") async def root(): return {"message": f"{settings.APP_NAME} is running!"}