# api.py — Thin orchestrator (routes live in routes/*.py) # # Monolith backup: api_monolith_backup.py # To revert: cp api_monolith_backup.py api.py from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from utils.logger import get_logger from utils.log_config import load_config as load_log_config import time from fnmatch import fnmatch import nest_asyncio nest_asyncio.apply() # Initialize API logger logger = get_logger('api') api_requests_logger = get_logger('api.requests') app = FastAPI() # ========== Global Exception Handler ========== @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): """Catch all unhandled exceptions and log them properly.""" logger.error(f"Unhandled exception on {request.method} {request.url.path}: {exc}", exc_info=True) return {"success": False, "error": "Internal server error"} # ========== Logging Middleware ========== @app.middleware("http") async def log_requests(request: Request, call_next): """Middleware to log HTTP requests based on configuration.""" start_time = time.time() # Get logging config log_config = load_log_config() api_config = log_config.get('components', {}).get('api.requests', {}) # Check if API request logging is enabled if not api_config.get('enabled', False): return await call_next(request) # Get filters filters = api_config.get('filters', {}) exclude_paths = filters.get('exclude_paths', []) exclude_status = filters.get('exclude_status', []) include_slow_requests = filters.get('include_slow_requests', True) slow_threshold_ms = filters.get('slow_threshold_ms', 1000) # Process request response = await call_next(request) # Calculate duration duration_ms = (time.time() - start_time) * 1000 # Check if path should be excluded path = request.url.path for pattern in exclude_paths: if fnmatch(path, pattern): return response # Check if status should be excluded (unless it's a slow request) is_slow = duration_ms >= slow_threshold_ms if response.status_code in exclude_status and not (include_slow_requests and is_slow): return response # Log the request log_msg = f"{request.method} {path} - {response.status_code} ({duration_ms:.2f}ms)" if is_slow: api_requests_logger.warning(f"SLOW REQUEST: {log_msg}") elif response.status_code >= 500: api_requests_logger.error(log_msg) elif response.status_code >= 400: api_requests_logger.warning(log_msg) else: api_requests_logger.api(log_msg) return response # Serve static folder app.mount("/static", StaticFiles(directory="static"), name="static") # ========== Include Route Modules ========== from routes.core import router as core_router from routes.mood import router as mood_router from routes.language import router as language_router from routes.evil_mode import router as evil_mode_router from routes.bipolar_mode import router as bipolar_mode_router from routes.gpu import router as gpu_router from routes.bot_actions import router as bot_actions_router from routes.autonomous import router as autonomous_router from routes.profile_picture import router as profile_picture_router from routes.manual_send import router as manual_send_router from routes.servers import router as servers_router from routes.figurines import router as figurines_router from routes.dms import router as dms_router from routes.image_generation import router as image_generation_router from routes.chat import router as chat_router from routes.config import router as config_router from routes.logging_config import router as logging_config_router from routes.voice import router as voice_router from routes.memory import router as memory_router app.include_router(core_router) app.include_router(mood_router) app.include_router(language_router) app.include_router(evil_mode_router) app.include_router(bipolar_mode_router) app.include_router(gpu_router) app.include_router(bot_actions_router) app.include_router(autonomous_router) app.include_router(profile_picture_router) app.include_router(manual_send_router) app.include_router(servers_router) app.include_router(figurines_router) app.include_router(dms_router) app.include_router(image_generation_router) app.include_router(chat_router) app.include_router(config_router) app.include_router(logging_config_router) app.include_router(voice_router) app.include_router(memory_router) def start_api(): import uvicorn uvicorn.run(app, host="0.0.0.0", port=3939)