Add per-request cross_check toggle to the HTTP service (lazy-loaded)

POST /remove-background gains an optional cross_check form field
(1/0/true/false/yes/no/on/off; empty = service default). The effective
state is reported in the X-BGFilter-Cross-Check response header.

The cross-check model is now never preloaded at startup: the first
request that enables it pays the one-time load (measured ~8 s on top of
the ~50 s cc inference), after which the instance is cached and shared.

Verified with a functional test against PipelineManager: cc-off requests
never load the model, cc=1 lazy-loads then reuses the cached instance,
and omitting the field falls back to the service default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-04 22:34:08 +08:00
parent 11c591e5b5
commit 8417653598
3 changed files with 51 additions and 11 deletions
+22 -1
View File
@@ -129,6 +129,20 @@ def _normalize_seg_model(value: str | None) -> str | None:
return v
def _normalize_cross_check(value: str | None) -> bool | None:
"""None/empty -> use the service default; otherwise a boolean string."""
if value is None:
return None
v = value.strip().lower()
if v == "":
return None
if v in ("1", "true", "yes", "on"):
return True
if v in ("0", "false", "no", "off"):
return False
raise HTTPException(status_code=400, detail="invalid cross_check")
def _decode_image(data: bytes) -> np.ndarray:
if not data:
raise HTTPException(status_code=400, detail="empty image")
@@ -162,12 +176,15 @@ async def remove_background(
file: UploadFile = File(...),
screen_color: str | None = Form(None),
seg_model: str | None = Form(None),
cross_check: str | None = Form(None),
):
if _manager is None:
raise HTTPException(status_code=503, detail="service not ready")
normalized_color = _normalize_screen_color(screen_color)
normalized_seg = _normalize_seg_model(seg_model) or _manager.default_seg_model
normalized_cc = _normalize_cross_check(cross_check)
effective_cc = normalized_cc if normalized_cc is not None else _manager.cross_check_enabled
rgb = _decode_image(await file.read())
@@ -178,7 +195,10 @@ async def remove_background(
result = await loop.run_in_executor(
None,
lambda: _manager.process(
rgb, screen_color=normalized_color, seg_model=normalized_seg
rgb,
screen_color=normalized_color,
seg_model=normalized_seg,
cross_check=normalized_cc,
),
)
except RuntimeError as exc:
@@ -200,5 +220,6 @@ async def remove_background(
"X-BGFilter-Elapsed-Ms": str(elapsed_ms),
"X-BGFilter-Seg-Model": normalized_seg,
"X-BGFilter-Screen-Color": normalized_color if normalized_color else "auto",
"X-BGFilter-Cross-Check": "on" if effective_cc else "off",
}
return Response(content=png, media_type="image/png", headers=headers)