feat: harden pipeline UX — preprocess, rembg alpha, remix/lightbox
Downscale to 2000px JPEG before rembg, random blend opacity, timeout retries, per-variant remix prefill, lightbox, and longer SFTP idle. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+40
-2
@@ -8,7 +8,7 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
from urllib.parse import quote
|
||||
|
||||
from fastapi import FastAPI, Form, HTTPException, Request
|
||||
from fastapi import FastAPI, Form, HTTPException, Query, Request
|
||||
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
@@ -119,13 +119,49 @@ def job_file(job_id: str, rel_path: str) -> FileResponse:
|
||||
|
||||
|
||||
@app.get("/jobs/{job_id}/remix", response_class=HTMLResponse)
|
||||
def remix_form(request: Request, job_id: str, error: str | None = None) -> HTMLResponse:
|
||||
def remix_form(
|
||||
request: Request,
|
||||
job_id: str,
|
||||
error: str | None = None,
|
||||
from_variant: str | None = Query(None, alias="from"),
|
||||
) -> HTMLResponse:
|
||||
job_root = _job_root(job_id)
|
||||
if not (job_root / "rembg.png").exists():
|
||||
raise HTTPException(status_code=409, detail="Job hat noch kein Rembg-Ergebnis, Remix noch nicht moeglich.")
|
||||
|
||||
assets = pipeline.load_assets()
|
||||
options = remix.build_remix_options(assets)
|
||||
prefill: dict[str, str] = {
|
||||
"bg_filter": "",
|
||||
"bg_blend": "",
|
||||
"fg_filter": "",
|
||||
"fg_blend": "",
|
||||
"opacity": config.BLEND_OPACITY if config.BLEND_OPACITY in config.OPACITY_CHOICES else "30%",
|
||||
}
|
||||
if from_variant:
|
||||
manifest = pipeline.read_manifest(job_id) or {}
|
||||
match = next((v for v in manifest.get("variants", []) if v.get("id") == from_variant), None)
|
||||
if match:
|
||||
opacity = match.get("blend_opacity") or prefill["opacity"]
|
||||
if opacity not in config.OPACITY_CHOICES:
|
||||
# Snap odd random values (e.g. 37%) to nearest offered choice.
|
||||
try:
|
||||
pct = int(str(opacity).rstrip("%"))
|
||||
nearest = min(
|
||||
config.OPACITY_CHOICES,
|
||||
key=lambda c: abs(int(c.rstrip("%")) - pct),
|
||||
)
|
||||
opacity = nearest
|
||||
except ValueError:
|
||||
opacity = prefill["opacity"]
|
||||
prefill = {
|
||||
"bg_filter": match.get("background_filter") or "",
|
||||
"bg_blend": match.get("background_blend") or "",
|
||||
"fg_filter": match.get("foreground_filter") or "",
|
||||
"fg_blend": match.get("foreground_blend") or "",
|
||||
"opacity": opacity,
|
||||
}
|
||||
|
||||
return templates.TemplateResponse(
|
||||
"remix.html",
|
||||
{
|
||||
@@ -134,6 +170,8 @@ def remix_form(request: Request, job_id: str, error: str | None = None) -> HTMLR
|
||||
"job_id": job_id,
|
||||
"options": options,
|
||||
"opacity_choices": config.OPACITY_CHOICES,
|
||||
"prefill": prefill,
|
||||
"from_variant": from_variant,
|
||||
"error": error,
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user