""" main.py — FastAPI application entry point. """ import os import mimetypes # Fix for missing PDF MIME type on some Linux environments (Hugging Face) mimetypes.add_type('application/pdf', '.pdf') mimetypes.add_type('image/png', '.png') from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from config import INDEXES_DIR from indexes import load_indexes from routes import router, limiter from slowapi.errors import RateLimitExceeded from slowapi import _rate_limit_exceeded_handler @asynccontextmanager async def lifespan(app: FastAPI): """Load all indexes and models at startup.""" print("DEBUG: Application starting up and loading indexes...") load_indexes() yield app = FastAPI( title = "CONTROLSAI API", description = "Siemens S7-1200 RAG Backend — Sprint 1", version = "1.0.0", lifespan = lifespan, ) app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) # ── CORS ───────────────────────────────────────────────────────────────────── ALLOWED_ORIGINS = [ "http://localhost:5173", "http://localhost:3000", "https://*.vercel.app", "https://*.hf.space" ] app.add_middleware( CORSMiddleware, allow_origins = ALLOWED_ORIGINS, allow_origin_regex = r"^https://.*\.vercel\.app$|^https://.*\.hf\.space$", allow_methods = ["*"], allow_headers = ["*"], ) # ── Static File Mounts ─────────────────────────────────────────────────────── class SafeStaticFiles(StaticFiles): """Subclass of StaticFiles to inject CORS headers for PDF rendering.""" def set_headers(self, response, stat_result): # Allow cross-origin access response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Cross-Origin-Resource-Policy"] = "cross-origin" # Content-Type is now handled automatically by the mimetypes.add_type fix above super().set_headers(response, stat_result) # Ensure paths are absolute (fixes HF Space mounting issues) BASE_DIR = os.path.dirname(os.path.abspath(__file__)) abs_indexes_dir = os.path.join(BASE_DIR, "indexes") pdfs_dir = os.path.join(abs_indexes_dir, "pdfs") if os.path.exists(pdfs_dir): print(f"DEBUG: Checking PDFs folder at {pdfs_dir}") files = os.listdir(pdfs_dir) print(f"DEBUG: Found {len(files)} files in pdfs directory.") for f in files: f_path = os.path.join(pdfs_dir, f) size_mb = os.path.getsize(f_path) / (1024 * 1024) print(f"DEBUG: File: {f} | Size: {size_mb:.2f} MB") app.mount("/pdfs", SafeStaticFiles(directory=pdfs_dir), name="pdfs") else: print(f"DEBUG ERROR: PDFs folder NOT found at {pdfs_dir}") images_dir = os.path.join(abs_indexes_dir, "images") if os.path.exists(images_dir): app.mount("/images", SafeStaticFiles(directory=images_dir), name="images") # ── Routes ─────────────────────────────────────────────────────────────────── app.include_router(router)