Spaces:
Build error
Build error
| """ | |
| Chronos-2 Forecasting API - Clean Architecture Version 3.0 | |
| Este es el punto de entrada de la aplicación, refactorizado siguiendo | |
| Clean Architecture y principios SOLID. | |
| Características: | |
| - Arquitectura en capas (Presentation, Application, Domain, Infrastructure) | |
| - Dependency Injection completa | |
| - Separación de responsabilidades | |
| - Código mantenible y testeable | |
| """ | |
| from fastapi import FastAPI | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.responses import FileResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| import os | |
| from app.infrastructure.config.settings import get_settings | |
| from app.utils.logger import setup_logger | |
| # Import routers | |
| from app.api.routes import ( | |
| health_router, | |
| forecast_router, | |
| anomaly_router, | |
| backtest_router | |
| ) | |
| logger = setup_logger(__name__) | |
| settings = get_settings() | |
| # ============================================================================ | |
| # Create FastAPI App | |
| # ============================================================================ | |
| app = FastAPI( | |
| title=settings.api_title, | |
| version=settings.api_version, | |
| description=settings.api_description, | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| openapi_url="/openapi.json" | |
| ) | |
| # ============================================================================ | |
| # Middleware | |
| # ============================================================================ | |
| # CORS Middleware | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=settings.cors_origins, | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ============================================================================ | |
| # API Routes | |
| # ============================================================================ | |
| # Health check endpoint (temporal, será movido a routes/health.py) | |
| async def health_check(): | |
| """Check if the API is running and model is loaded.""" | |
| from app.api.dependencies import get_forecast_model | |
| try: | |
| model = get_forecast_model() | |
| model_info = model.get_model_info() | |
| return { | |
| "status": "ok", | |
| "version": settings.api_version, | |
| "model": model_info | |
| } | |
| except Exception as e: | |
| logger.error(f"Health check failed: {e}") | |
| return { | |
| "status": "error", | |
| "version": settings.api_version, | |
| "error": str(e) | |
| } | |
| # Include routers | |
| app.include_router(health_router) | |
| app.include_router(forecast_router) | |
| app.include_router(anomaly_router) | |
| app.include_router(backtest_router) | |
| # ============================================================================ | |
| # Static Files (Excel Add-in) | |
| # ============================================================================ | |
| if os.path.exists(settings.static_dir): | |
| logger.info(f"Mounting static files from: {settings.static_dir}") | |
| # Mount subdirectories | |
| for subdir in ["assets", "taskpane", "commands"]: | |
| path = os.path.join(settings.static_dir, subdir) | |
| if os.path.exists(path): | |
| app.mount(f"/{subdir}", StaticFiles(directory=path), name=subdir) | |
| logger.info(f"Mounted /{subdir}") | |
| # Manifest file | |
| manifest_path = os.path.join(settings.static_dir, "manifest.xml") | |
| if os.path.exists(manifest_path): | |
| async def get_manifest(): | |
| """Serve Excel Add-in manifest.""" | |
| return FileResponse(manifest_path, media_type="application/xml") | |
| logger.info("Manifest endpoint registered") | |
| else: | |
| logger.warning(f"Static directory not found: {settings.static_dir}") | |
| # ============================================================================ | |
| # Startup/Shutdown Events | |
| # ============================================================================ | |
| async def startup_event(): | |
| """Initialize resources on startup.""" | |
| logger.info("=" * 60) | |
| logger.info(f"🚀 {settings.api_title} v{settings.api_version}") | |
| logger.info("=" * 60) | |
| logger.info("Architecture: Clean Architecture (4 layers)") | |
| logger.info("Principles: SOLID") | |
| logger.info(f"Model: {settings.model_id}") | |
| logger.info(f"Device: {settings.device_map}") | |
| logger.info("=" * 60) | |
| # Pre-load model | |
| try: | |
| from app.api.dependencies import get_forecast_model | |
| logger.info("Pre-loading forecast model...") | |
| model = get_forecast_model() | |
| logger.info(f"✅ Model loaded: {model.get_model_info()}") | |
| except Exception as e: | |
| logger.error(f"❌ Failed to load model: {e}") | |
| logger.error("API will start but forecasting will fail until model loads") | |
| async def shutdown_event(): | |
| """Cleanup resources on shutdown.""" | |
| logger.info("=" * 60) | |
| logger.info("Shutting down Chronos-2 API...") | |
| logger.info("=" * 60) | |
| # ============================================================================ | |
| # Root Endpoint | |
| # ============================================================================ | |
| async def root(): | |
| """API information and documentation links.""" | |
| return { | |
| "name": settings.api_title, | |
| "version": settings.api_version, | |
| "description": settings.api_description, | |
| "docs": "/docs", | |
| "health": "/health", | |
| "architecture": "Clean Architecture with SOLID principles", | |
| "layers": { | |
| "presentation": "FastAPI (app/api/)", | |
| "application": "Use Cases (app/application/)", | |
| "domain": "Business Logic (app/domain/)", | |
| "infrastructure": "External Services (app/infrastructure/)" | |
| } | |
| } | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run( | |
| "app.main_v3:app", | |
| host="0.0.0.0", | |
| port=settings.api_port, | |
| reload=True, | |
| log_level=settings.log_level.lower() | |
| ) | |