import logging from logging.handlers import RotatingFileHandler import os from dotenv import load_dotenv # Cargar variables de entorno load_dotenv() from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from app.database import engine, Base from app.models.user import User from app.models.process import Task from app.models.sync import MigrationBackup from app.routers import auth, songs, lyrics, aprendizaje, alabanza, migration from app.routers import iglesia as iglesia_router import app.models.iglesia # Registra las tablas de iglesia en Base import app.models.aprendizaje # Registra las tablas de aprendizaje en Base import app.models.sync # Registra las tablas de sync en Base # ========================================== # CONFIGURACIÓN DE LOGGING # ========================================== # Crear directorio de logs LOGS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logs") os.makedirs(LOGS_DIR, exist_ok=True) # Configurar logging logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ # Rotating file handler (10MB max, 5 backups) RotatingFileHandler( os.path.join(LOGS_DIR, "melodix.log"), maxBytes=10*1024*1024, backupCount=5, encoding='utf-8' ), # Console handler logging.StreamHandler() ] ) logger = logging.getLogger(__name__) # ========================================== # CREAR TABLAS # ========================================== logger.info("Inicializando base de datos...") # Descomentado para crear tablas automáticamente si la DB está limpia Base.metadata.create_all(bind=engine) logger.info("Tablas de base de datos listas") # ========================================== # APP FASTAPI # ========================================== app = FastAPI( title="Melodix API", description="API para separación de pistas de audio usando IA (Demucs)", version="2.0.0" ) # ========================================== # CONFIGURACIÓN DE CORS # ========================================== # Leer orígenes permitidos desde variables de entorno allowed_origins_env = os.getenv("ALLOWED_ORIGINS", "") allowed_origins = [origin.strip() for origin in allowed_origins_env.split(",") if origin.strip()] # Si no hay orígenes específicos o está vacío, permitir todos (desarrollo) if not allowed_origins or allowed_origins == [""]: allowed_origins = ["*"] logger.warning("CORS: Permitiendo todos los orígenes para desarrollo (*)") else: logger.info(f"CORS: Orígenes permitidos: {allowed_origins}") app.add_middleware( CORSMiddleware, allow_origins=allowed_origins, allow_credentials=False, allow_methods=["*"], allow_headers=["*"], ) # ========================================== # CONFIGURACIÓN DE DIRECTORIOS # ========================================== BASE_DIR = os.path.dirname(os.path.abspath(__file__)) PROCESSED_DIR = os.path.join(BASE_DIR, "processed") UPLOADS_DIR = os.path.join(BASE_DIR, "uploads") os.makedirs(PROCESSED_DIR, exist_ok=True) os.makedirs(UPLOADS_DIR, exist_ok=True) logger.info(f"Directorio de procesados: {PROCESSED_DIR}") logger.info(f"Directorio de uploads: {UPLOADS_DIR}") # Servir archivos estáticos (audios procesados) app.mount("/audios", StaticFiles(directory=PROCESSED_DIR), name="audios") logger.info("Servidor de archivos estáticos configurado en /audios") # ========================================== # INCLUIR ROUTERS # ========================================== app.include_router(auth.router) app.include_router(songs.router) app.include_router(lyrics.router) app.include_router(iglesia_router.router) app.include_router(aprendizaje.router) app.include_router(alabanza.router) app.include_router(migration.router) logger.info("Routers registrados: auth, songs, lyrics, iglesia, aprendizaje, alabanza, migration") # ========================================== # ENDPOINTS # ========================================== @app.get("/") def read_root(): logger.info("Request recibido en /") return {"message": "Melodix API is running", "version": "2.0.0"} @app.options("/{rest_of_path:path}") async def preflight_fallback(rest_of_path: str): return {"message": "CORS preflight fallback"} @app.get("/health") def health_check(): """Endpoint para verificar el estado de la API""" return { "status": "healthy", "api": "running", "version": "2.0.0" } # ========================================== # STARTUP/SHUTDOWN EVENTS # ========================================== @app.on_event("startup") async def startup_event(): logger.info("=" * 50) logger.info("MELODIX API INICIANDO") logger.info("=" * 50) @app.on_event("shutdown") async def shutdown_event(): logger.info("=" * 50) logger.info("MELODIX API DETENIÉNDOSE") logger.info("=" * 50)