"""FastAPI backend for garment photo cleaning.""" import os from pathlib import Path from fastapi import FastAPI, File, Form, HTTPException, UploadFile, status from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse, JSONResponse from fastapi.staticfiles import StaticFiles from cleaner import ( DEFAULT_MODEL, CleanerError, _get_image_info, build_prompt, clean_garment, encode_image_bytes, ) DEFAULT_PROMPT = build_prompt("beige") STATIC_DIR = Path(__file__).resolve().parent / "static" STATIC_DIR.mkdir(parents=True, exist_ok=True) app = FastAPI(title="unwrap-clothes") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/api/health") def health_check(): return {"status": "ok"} @app.get("/") def read_root(): index_file = STATIC_DIR / "index.html" if index_file.is_file(): return FileResponse(index_file) return JSONResponse({"status": "ok", "message": "unwrap-clothes backend is running"}) @app.post("/api/clean") async def clean_endpoint( file: UploadFile = File(...), prompt: str = Form(default=DEFAULT_PROMPT), model: str = Form(default=DEFAULT_MODEL), api_key: str | None = Form(default=None), restore_res: bool = Form(default=True), ): effective_api_key = (api_key.strip() if api_key and api_key.strip() else None) or os.environ.get( "OPENROUTER_API_KEY" ) if not effective_api_key: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="API key is required. Provide it in the form or set OPENROUTER_API_KEY.", ) file_bytes = await file.read() if not file_bytes: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Uploaded file is empty.", ) orig_dims, _ = _get_image_info(file_bytes) if orig_dims is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid image file. Could not decode image.", ) try: clean_result = clean_garment( image_data=file_bytes, prompt=prompt, api_key=effective_api_key, model=model, restore_res=restore_res, ) except CleanerError as exc: raise HTTPException( status_code=status.HTTP_502_BAD_GATEWAY, detail=str(exc), ) return { "image": encode_image_bytes(clean_result.image_bytes, mime=clean_result.media_type), "cost": clean_result.cost, "width": clean_result.width, "height": clean_result.height, "original_dimensions": list(clean_result.original_dimensions) if clean_result.original_dimensions else None, "model_dimensions": list(clean_result.model_dimensions) if clean_result.model_dimensions else None, "was_rescaled": clean_result.was_rescaled, "media_type": clean_result.media_type, } if STATIC_DIR.is_dir(): app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static") if __name__ == "__main__": import uvicorn uvicorn.run("app:app", host="127.0.0.1", port=8000, reload=True)