|
|
""" |
|
|
FastAPI Main Application |
|
|
""" |
|
|
import sys |
|
|
import os |
|
|
from pathlib import Path |
|
|
from contextlib import asynccontextmanager |
|
|
from fastapi import FastAPI |
|
|
from fastapi.middleware.cors import CORSMiddleware |
|
|
from fastapi.responses import JSONResponse |
|
|
from loguru import logger |
|
|
|
|
|
from app.config import settings |
|
|
from app.core.redis_client import get_redis_client |
|
|
from app.api.routes import router |
|
|
|
|
|
|
|
|
|
|
|
logger.remove() |
|
|
logger.add( |
|
|
sys.stdout, |
|
|
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan> - <level>{message}</level>", |
|
|
level=settings.LOG_LEVEL |
|
|
) |
|
|
|
|
|
|
|
|
try: |
|
|
log_dir = Path("logs") |
|
|
log_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
logger.add( |
|
|
"logs/swara_api_{time:YYYY-MM-DD}.log", |
|
|
rotation="1 day", |
|
|
retention="7 days", |
|
|
format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function} - {message}", |
|
|
level=settings.LOG_LEVEL |
|
|
) |
|
|
except (PermissionError, OSError) as e: |
|
|
|
|
|
logger.warning(f"Cannot create log file: {e}. Using stdout only.") |
|
|
|
|
|
|
|
|
@asynccontextmanager |
|
|
async def lifespan(app: FastAPI): |
|
|
""" |
|
|
Application lifespan events |
|
|
""" |
|
|
|
|
|
logger.info("=" * 70) |
|
|
logger.info("π SWARA API Starting...") |
|
|
logger.info("=" * 70) |
|
|
logger.info(f"Environment: {settings.ENV}") |
|
|
logger.info(f"API Version: {settings.API_VERSION}") |
|
|
logger.info(f"Redis URL: {settings.REDIS_URL}") |
|
|
|
|
|
|
|
|
try: |
|
|
redis_client = get_redis_client() |
|
|
redis_client.connect() |
|
|
logger.info("β Redis connection established") |
|
|
except Exception as e: |
|
|
logger.error(f"β Failed to connect to Redis: {e}") |
|
|
logger.warning("β API will start but background tasks will not work") |
|
|
|
|
|
|
|
|
settings.get_temp_dir() |
|
|
settings.get_models_dir() |
|
|
logger.info("β Directories created") |
|
|
|
|
|
logger.info("=" * 70) |
|
|
logger.info(f"β SWARA API Ready at http://{settings.API_HOST}:{settings.API_PORT}") |
|
|
logger.info("=" * 70) |
|
|
|
|
|
yield |
|
|
|
|
|
|
|
|
logger.info("=" * 70) |
|
|
logger.info("π SWARA API Shutting down...") |
|
|
logger.info("=" * 70) |
|
|
|
|
|
|
|
|
try: |
|
|
redis_client = get_redis_client() |
|
|
redis_client.disconnect() |
|
|
logger.info("β Redis disconnected") |
|
|
except: |
|
|
pass |
|
|
|
|
|
logger.info("β Shutdown complete") |
|
|
logger.info("=" * 70) |
|
|
|
|
|
|
|
|
|
|
|
app = FastAPI( |
|
|
title=settings.API_TITLE, |
|
|
version=settings.API_VERSION, |
|
|
description=settings.API_DESCRIPTION, |
|
|
lifespan=lifespan, |
|
|
docs_url="/docs", |
|
|
redoc_url="/redoc", |
|
|
openapi_url="/openapi.json" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
app.add_middleware( |
|
|
CORSMiddleware, |
|
|
allow_origins=["*"], |
|
|
allow_credentials=True, |
|
|
allow_methods=["*"], |
|
|
allow_headers=["*"], |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
app.include_router(router) |
|
|
|
|
|
|
|
|
|
|
|
@app.exception_handler(Exception) |
|
|
async def global_exception_handler(request, exc): |
|
|
"""Global exception handler""" |
|
|
logger.error(f"Unhandled exception: {exc}") |
|
|
return JSONResponse( |
|
|
status_code=500, |
|
|
content={ |
|
|
"error": "Internal server error", |
|
|
"detail": str(exc) if settings.ENV == "development" else "An unexpected error occurred" |
|
|
} |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
import uvicorn |
|
|
|
|
|
uvicorn.run( |
|
|
"app.main:app", |
|
|
host=settings.API_HOST, |
|
|
port=settings.API_PORT, |
|
|
reload=settings.ENV == "development", |
|
|
workers=settings.API_WORKERS |
|
|
) |
|
|
|