b09f90bfcc
CI / lint-and-test (pull_request) Failing after 9s
Prevent worker/web clobbering of meta variants via flock and merge-by-id, make filter timeouts thread-local, harden job-id/stem sanitization, migrate TemplateResponse API, and remove the compare-bg experiment. Co-authored-by: Cursor <cursoragent@cursor.com>
80 lines
2.7 KiB
Python
80 lines
2.7 KiB
Python
"""Remix: create one additional variant for an existing job, using the
|
|
cached original + rembg output and user-chosen filters/blends/opacity."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from dataclasses import dataclass
|
|
|
|
from . import pipeline
|
|
from .pipeline import FilterAssets, JobPaths, PipelineError
|
|
|
|
|
|
@dataclass
|
|
class RemixChoice:
|
|
bg_filter: str
|
|
bg_blend: str
|
|
fg_filter: str
|
|
fg_blend: str
|
|
opacity: str
|
|
|
|
|
|
def build_remix_options(assets: FilterAssets) -> dict[str, list[str]]:
|
|
return {
|
|
"background_filters": sorted(assets.background_names),
|
|
"foreground_filters": sorted(assets.foreground_names),
|
|
"blend_modes": sorted(assets.blend_modes),
|
|
}
|
|
|
|
|
|
def create_remix_variant(job_id: str, choice: RemixChoice) -> dict:
|
|
"""Compose exactly one variant from explicit choices and append it to
|
|
the job's meta. Raises PipelineError on failure (caller should show
|
|
it to the user, no half-written manifest entries are ever created)."""
|
|
stem = pipeline.sanitize_stem(job_id)
|
|
paths: JobPaths = pipeline.job_paths(stem, ".jpg")
|
|
if not paths.original.exists() or not paths.rembg.exists():
|
|
raise PipelineError("Original oder Rembg-Bild fehlt fuer diesen Job — Remix nicht moeglich.")
|
|
|
|
assets = pipeline.load_assets()
|
|
if choice.bg_filter not in assets.commands:
|
|
raise PipelineError(f"Unbekannter Background-Filter: {choice.bg_filter}")
|
|
if choice.fg_filter not in assets.commands:
|
|
raise PipelineError(f"Unbekannter Foreground-Filter: {choice.fg_filter}")
|
|
if choice.bg_blend not in assets.blend_modes or choice.fg_blend not in assets.blend_modes:
|
|
raise PipelineError("Unbekannter Blend-Modus.")
|
|
|
|
manifest = pipeline.read_manifest(stem) or {
|
|
"job_id": stem,
|
|
"original_file": paths.original.name,
|
|
"rembg_file": paths.rembg.name,
|
|
"source_stem": stem,
|
|
"created_at": pipeline.now_iso(),
|
|
"variants": [],
|
|
}
|
|
variant_stem = pipeline.resolve_source_stem(manifest, paths)
|
|
# Unique id avoids collisions when two remixes run in parallel.
|
|
variant_id = f"v{uuid.uuid4().hex[:8]}"
|
|
|
|
entry = pipeline.compose_variant(
|
|
paths,
|
|
assets,
|
|
variant_id=variant_id,
|
|
source="remix",
|
|
variant_stem=variant_stem,
|
|
bg_name=choice.bg_filter,
|
|
bg_mode=choice.bg_blend,
|
|
fg_name=choice.fg_filter,
|
|
fg_mode=choice.fg_blend,
|
|
opacity=choice.opacity,
|
|
)
|
|
pipeline.append_manifest_variant(
|
|
paths,
|
|
entry,
|
|
original_file=paths.original.name,
|
|
rembg_file=paths.rembg.name,
|
|
source_stem=variant_stem,
|
|
created_at=manifest.get("created_at") if isinstance(manifest.get("created_at"), str) else None,
|
|
)
|
|
return entry
|