diff --git a/backend/app/api/v1/routes.py b/backend/app/api/v1/routes.py index 5eac974..43bd6b6 100644 --- a/backend/app/api/v1/routes.py +++ b/backend/app/api/v1/routes.py @@ -1,9 +1,10 @@ -from fastapi import APIRouter, HTTPException, BackgroundTasks +from fastapi import APIRouter, BackgroundTasks from fastapi.responses import JSONResponse from backend.app.models.report_models import ReportRequest, ReportResponse from backend.app.services.report_service import generate_report, in_memory_reports, get_report_status_from_memory, get_report_data from backend.app.core.orchestrator import create_orchestrator from backend.app.core.logger import api_logger +from backend.app.core.exceptions import ReportNotFoundException, AgentExecutionException import asyncio router = APIRouter() @@ -28,13 +29,23 @@ async def dummy_agent_two(report_id: str, token_id: str) -> dict: async def read_root(): return {"message": "Welcome to API v1"} +async def _run_agents_in_background(report_id: str, token_id: str): + try: + await orchestrator_instance.execute_agents_concurrently(report_id, token_id) + except Exception as e: + api_logger.error(f"Agent execution failed for report {report_id}: {e}") + # Here you might want to update the report status to 'failed' in in_memory_reports + # For now, we'll just log it. + if report_id in in_memory_reports: + in_memory_reports[report_id]["status"] = "failed" + in_memory_reports[report_id]["detail"] = f"Agent execution failed: {e}" + @router.post("/report/generate", response_model=ReportResponse) async def generate_report_endpoint(request: ReportRequest, background_tasks: BackgroundTasks): api_logger.info(f"Received report generation request for token_id: {request.token_id}") report_response = await generate_report(request) report_id = report_response.report_id - # Execute agents concurrently in a background task - background_tasks.add_task(orchestrator_instance.execute_agents_concurrently, report_id, request.token_id) + background_tasks.add_task(_run_agents_in_background, report_id, request.token_id) return report_response @router.get("/reports/{report_id}/status") @@ -43,7 +54,7 @@ async def get_report_status(report_id: str): report = get_report_status_from_memory(report_id) if not report: api_logger.error(f"Report with id {report_id} not found for status request.") - raise HTTPException(status_code=404, detail="Report not found") + raise ReportNotFoundException(detail="Report not found") return {"report_id": report_id, "status": report["status"]} @router.get("/reports/{report_id}/data") @@ -74,4 +85,4 @@ async def get_report_data_endpoint(report_id: str): }, ) api_logger.error(f"Report with id {report_id} not found or not completed for data request.") - raise HTTPException(status_code=404, detail="Report not found or not completed") + raise ReportNotFoundException(detail="Report not found or not completed") diff --git a/backend/app/core/exceptions.py b/backend/app/core/exceptions.py new file mode 100644 index 0000000..e7f6705 --- /dev/null +++ b/backend/app/core/exceptions.py @@ -0,0 +1,10 @@ + +from fastapi import HTTPException, status + +class ReportNotFoundException(HTTPException): + def __init__(self, detail: str = "Report not found"): + super().__init__(status_code=status.HTTP_404_NOT_FOUND, detail=detail) + +class AgentExecutionException(HTTPException): + def __init__(self, detail: str = "Agent execution failed"): + super().__init__(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=detail) diff --git a/backend/main.py b/backend/main.py index 0cd2198..33f5a7b 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2,12 +2,59 @@ load_dotenv() -from fastapi import FastAPI +from fastapi import FastAPI, Request, HTTPException +from fastapi.responses import JSONResponse from backend.app.core.config import settings from backend.app.api.v1.routes import router as v1_router +from backend.app.core.exceptions import ReportNotFoundException, AgentExecutionException +from backend.app.core.logger import api_logger app = FastAPI(title=settings.APP_NAME, debug=settings.DEBUG) +@app.exception_handler(ReportNotFoundException) +async def report_not_found_exception_handler(request: Request, exc: ReportNotFoundException): + api_logger.error(f"ReportNotFoundException: {exc.detail}") + return JSONResponse( + status_code=exc.status_code, + content={ + "message": "Report not found", + "detail": exc.detail + }, + ) + +@app.exception_handler(AgentExecutionException) +async def agent_execution_exception_handler(request: Request, exc: AgentExecutionException): + api_logger.error(f"AgentExecutionException: {exc.detail}") + return JSONResponse( + status_code=exc.status_code, + content={ + "message": "Agent execution failed", + "detail": exc.detail + }, + ) + +@app.exception_handler(HTTPException) +async def http_exception_handler(request: Request, exc: HTTPException): + api_logger.error(f"HTTPException: {exc.detail} (Status Code: {exc.status_code})") + return JSONResponse( + status_code=exc.status_code, + content={ + "message": exc.detail, + "detail": exc.detail + }, + ) + +@app.exception_handler(Exception) +async def generic_exception_handler(request: Request, exc: Exception): + api_logger.exception(f"Unhandled exception: {exc}") + return JSONResponse( + status_code=500, + content={ + "message": "Internal Server Error", + "detail": "An unexpected error occurred." + } + ) + app.include_router(v1_router, prefix="/api/v1") @app.get("/health")