from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse, HTMLResponse from contextlib import asynccontextmanager from pathlib import Path import os from app.config import settings from app.database import init_db from app.routers import projects, edits, images, patches, generate, tools @asynccontextmanager async def lifespan(app: FastAPI): """Initialize database on startup""" init_db() yield app = FastAPI( title="AI Photo Edit API", description="API for AI-powered photo editing with mask-scoped regeneration", version="1.0.0", lifespan=lifespan ) # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins_list, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(projects.router) app.include_router(edits.router) app.include_router(images.router) app.include_router(patches.router) app.include_router(generate.router) app.include_router(tools.router) @app.get("/api") def api_root(): """API info endpoint""" return { "name": "AI Photo Edit API", "version": "1.0.0", "status": "running" } @app.get("/health") def health(): """Health check endpoint""" return {"status": "healthy"} # Static files directory STATIC_DIR = Path("/app/static") # Serve static assets (JS, CSS, images) if STATIC_DIR.exists(): app.mount("/assets", StaticFiles(directory=STATIC_DIR / "assets"), name="assets") @app.get("/", response_class=HTMLResponse) async def serve_spa(): """Serve React SPA index.html""" index_path = STATIC_DIR / "index.html" if index_path.exists(): return FileResponse(index_path) return HTMLResponse("

Frontend not built. Run npm build in frontend/

") @app.get("/{full_path:path}") async def serve_spa_routes(request: Request, full_path: str): """ Catch-all route for React Router (SPA). Serves static files if they exist, otherwise returns index.html. """ # Don't catch API routes if full_path.startswith(("projects", "edits", "patches", "tools", "generate", "health", "docs", "openapi.json", "api")): return {"detail": "Not Found"} # Check if it's a static file static_file = STATIC_DIR / full_path if static_file.exists() and static_file.is_file(): return FileResponse(static_file) # Otherwise serve index.html for React Router index_path = STATIC_DIR / "index.html" if index_path.exists(): return FileResponse(index_path) return HTMLResponse("

Frontend not built

", status_code=404)