| | """ |
| | Main FastAPI application for FinAgent backend. |
| | Chat2Sanction - AI-powered loan processing platform. |
| | """ |
| |
|
| | import os |
| | from contextlib import asynccontextmanager |
| |
|
| | from app.config import settings |
| | from app.routers import admin, auth, chat, loan |
| | from app.utils.logger import setup_logger |
| | from fastapi import FastAPI |
| | from fastapi.middleware.cors import CORSMiddleware |
| | from fastapi.responses import JSONResponse |
| |
|
| | |
| | logger = setup_logger("finagent", log_file="finagent.log") |
| |
|
| |
|
| | @asynccontextmanager |
| | async def lifespan(app: FastAPI): |
| | """ |
| | Lifespan context manager for startup and shutdown events. |
| | """ |
| | |
| | logger.info("=" * 80) |
| | logger.info(f"Starting {settings.APP_NAME} v{settings.APP_VERSION}") |
| | logger.info("=" * 80) |
| | logger.info(f"Environment: {'Development' if settings.DEBUG else 'Production'}") |
| | logger.info(f"Firebase Project: {settings.FIREBASE_PROJECT_ID}") |
| | logger.info(f"LLM Model: {getattr(settings, 'GEMINI_MODEL', 'Not configured')}") |
| |
|
| |
|
| | |
| | try: |
| | from app.agents.master_agent import master_agent |
| | from app.services.firebase_service import firebase_service |
| | from app.services.pdf_service import pdf_service |
| | from app.services.session_service import session_service |
| | from app.services.underwriting_service import underwriting_service |
| |
|
| | logger.info("All services initialized successfully") |
| | except Exception as e: |
| | logger.error(f"Failed to initialize services: {str(e)}") |
| |
|
| | |
| | os.makedirs(settings.PDF_OUTPUT_DIR, exist_ok=True) |
| | logger.info(f"PDF output directory: {settings.PDF_OUTPUT_DIR}") |
| |
|
| | logger.info("✓ Application startup complete") |
| | logger.info("=" * 80) |
| |
|
| | yield |
| |
|
| | |
| | logger.info("=" * 80) |
| | logger.info("Shutting down application") |
| | logger.info("=" * 80) |
| |
|
| |
|
| | |
| | app = FastAPI( |
| | title=settings.APP_NAME, |
| | description="AI-powered loan processing platform with conversational interface", |
| | version=settings.APP_VERSION, |
| | lifespan=lifespan, |
| | docs_url="/api/docs", |
| | redoc_url="/api/redoc", |
| | openapi_url="/api/openapi.json", |
| | ) |
| |
|
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=settings.ALLOWED_ORIGINS, |
| | allow_credentials=True, |
| | allow_methods=["*"], |
| | allow_headers=["*"], |
| | ) |
| |
|
| |
|
| | |
| | @app.get("/") |
| | async def root(): |
| | """Root endpoint with API information.""" |
| | return { |
| | "name": settings.APP_NAME, |
| | "version": settings.APP_VERSION, |
| | "status": "running", |
| | "docs": "/api/docs", |
| | } |
| |
|
| |
|
| | @app.get("/health") |
| | async def health_check(): |
| | """Health check endpoint.""" |
| | from app.services.firebase_service import firebase_service |
| |
|
| | return { |
| | "status": "healthy", |
| | "firebase": "connected" if firebase_service.initialized else "disconnected", |
| | "gemini": "configured" if settings.GOOGLE_API_KEY else "not configured", |
| | } |
| |
|
| |
|
| | |
| | app.include_router(auth.router, prefix="/api/auth", tags=["Authentication"]) |
| | app.include_router(chat.router, prefix="/api/chat", tags=["Chat"]) |
| | app.include_router(loan.router, prefix="/api/loan", tags=["Loans"]) |
| | app.include_router(admin.router, prefix="/api/admin", tags=["Admin"]) |
| |
|
| |
|
| | |
| | @app.exception_handler(Exception) |
| | async def global_exception_handler(request, exc): |
| | """Global exception handler for unhandled errors.""" |
| | logger.error(f"Unhandled exception: {str(exc)}", exc_info=True) |
| | return JSONResponse( |
| | status_code=500, |
| | content={ |
| | "error": "Internal server error", |
| | "detail": str(exc) if settings.DEBUG else "An unexpected error occurred", |
| | }, |
| | ) |
| |
|
| |
|
| | |
| | @app.middleware("http") |
| | async def log_requests(request, call_next): |
| | """Log all HTTP requests.""" |
| | from time import time |
| |
|
| | start_time = time() |
| |
|
| | |
| | response = await call_next(request) |
| |
|
| | |
| | duration = (time() - start_time) * 1000 |
| | logger.info( |
| | f"{request.method} {request.url.path} - {response.status_code} ({duration:.2f}ms)" |
| | ) |
| |
|
| | return response |
| |
|
| |
|
| | if __name__ == "__main__": |
| | import uvicorn |
| |
|
| | uvicorn.run( |
| | "app.main:app", |
| | host=settings.HOST, |
| | port=settings.PORT, |
| | reload=settings.DEBUG, |
| | workers=settings.WORKERS, |
| | ) |
| |
|