cardserver / app /main.py
GitHub Actions
πŸš€ Auto-deploy from GitHub
1788936
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from .api.v1.endpoints import generate, download, health, auth
from .core.config import settings
from .core.model_loader import get_generator # Import get_generator
from contextlib import asynccontextmanager
from pathlib import Path
import logging
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Ensure all required directories exist
settings.resolved_generated_path.mkdir(parents=True, exist_ok=True)
settings.resolved_base_path.mkdir(parents=True, exist_ok=True)
settings.resolved_symbols_path.mkdir(parents=True, exist_ok=True)
settings.resolved_qr_code_path.mkdir(parents=True, exist_ok=True)
# Ensure the static mount directory exists
settings.resolved_static_files_mount_dir.mkdir(parents=True, exist_ok=True)
# Lifecycle management for the model
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: Preload the model (non-blocking)
logger.info("Anwendung startet... Starte LLM-Modell-Loading im Hintergrund.")
try:
# Start model loading in background to avoid blocking app startup
import asyncio
import threading
def load_model_background():
try:
logger.info("Hintergrund-Loading des LLM-Modells gestartet...")
get_generator() # Calls get_generator to load and cache the model
logger.info("βœ… LLM-Modell erfolgreich vorab geladen und Pipeline initialisiert.")
except Exception as e:
logger.error(f"❌ Fehler beim Hintergrund-Loading des LLM-Modells: {e}", exc_info=True)
# Start model loading in a separate thread
model_thread = threading.Thread(target=load_model_background, daemon=True)
model_thread.start()
logger.info("πŸš€ Anwendung gestartet - Modell lΓ€dt im Hintergrund...")
except Exception as e:
logger.error(f"Fehler beim Starten des Hintergrund-Loadings: {e}", exc_info=True)
yield
# Shutdown: Cleanup actions could go here (not currently needed for the model)
logger.info("Anwendung wird heruntergefahren.")
app = FastAPI(
title=settings.PROJECT_NAME,
description="Ein Service zur Generierung personalisierter Horoskopkarten mit LoRa und FastAPI.",
version=settings.APP_VERSION,
lifespan=lifespan
)
# Mount static files with error handling
try:
static_dir = settings.resolved_static_files_mount_dir
logger.info(f"Attempting to mount static directory: {static_dir}")
logger.info(f"Static directory exists: {static_dir.exists()}")
if static_dir.exists():
app.mount(f"{settings.API_PREFIX}/static", StaticFiles(directory=static_dir), name="static")
logger.info("Static files mounted successfully")
else:
logger.warning(f"Static directory does not exist: {static_dir}")
logger.info("Creating static directory structure...")
static_dir.mkdir(parents=True, exist_ok=True)
# Create basic subdirectories
(static_dir / "images").mkdir(exist_ok=True)
(static_dir / "fonts").mkdir(exist_ok=True)
app.mount(f"{settings.API_PREFIX}/static", StaticFiles(directory=static_dir), name="static")
logger.info("Static files mounted with created directory")
except Exception as e:
logger.error(f"Failed to mount static files: {e}")
# Continue without static files mounting in case of error
origins = [
"http://localhost",
"http://localhost:3000",
"https://huggingface.co",
"https://ch404-cardserver.hf.space",
"https://huggingface.co/spaces/ch404/cardserver",
"*", # Allow all origins for debugging
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(health.router, prefix=settings.API_PREFIX, tags=["Health"])
app.include_router(auth.router, prefix=settings.API_PREFIX, tags=["Authentication"])
app.include_router(generate.router, prefix=settings.API_PREFIX, tags=["Generate Card"])
app.include_router(download.router, prefix=settings.API_PREFIX, tags=["Download Card"])
@app.get("/")
async def root():
return {"message": f"Welcome to the {settings.PROJECT_NAME} API."}