unwrap-clothes/app.py

112 lines
3.1 KiB
Python

"""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,
build_prompt,
clean_garment,
get_image_info,
resolve_api_key,
)
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 | None = File(default=None),
image: UploadFile | None = File(default=None),
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),
restore_resolution: bool | None = Form(default=None),
):
upload_file = file or image
if upload_file is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Image file is required (field 'file' or 'image').",
)
effective_restore = restore_resolution if restore_resolution is not None else restore_res
effective_api_key = resolve_api_key(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.",
)
try:
file_bytes = await upload_file.read()
finally:
await upload_file.close()
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=effective_restore,
)
except CleanerError as exc:
raise HTTPException(
status_code=status.HTTP_502_BAD_GATEWAY,
detail=str(exc),
)
return clean_result.to_payload()
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)