From f0bac67edb7e3b47ae1c05794d3cb511a4c39d88 Mon Sep 17 00:00:00 2001 From: MODELBEAST Date: Mon, 13 Jul 2026 01:37:56 +1000 Subject: [PATCH] Local mflux operators: seedvr2_upscale + mflux_image_edit (free, ungated) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two new local image-prep operators through the already-installed mflux 0.18 (no new heavy install, ungated weights): - seedvr2_upscale: mflux-upscale-seedvr2 (ByteDance SeedVR2, MIT) — faithful local upscale, free alternative to cloud fal_upscale - mflux_image_edit: mflux-generate-qwen-edit (Qwen-Image-Edit, Apache-2.0) — local prompt-based image editing, free alternative to fal_image_edit Research verdict on dinov3 (recorded): waiting for Meta approval is the only legitimate path — TRELLIS.2's DiT is trained on DINOv3 ViT-L/16 features so the encoder can't be swapped, and the only ungated mirrors are unauthorized re-uploads. trellis_mac stays blocked on the pending gate. Co-Authored-By: Claude Opus 4.8 --- .../operators/mflux_image_edit/manifest.json | 20 ++++++++ server/operators/mflux_image_edit/run.py | 48 +++++++++++++++++++ .../operators/seedvr2_upscale/manifest.json | 20 ++++++++ server/operators/seedvr2_upscale/run.py | 47 ++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 server/operators/mflux_image_edit/manifest.json create mode 100644 server/operators/mflux_image_edit/run.py create mode 100644 server/operators/seedvr2_upscale/manifest.json create mode 100644 server/operators/seedvr2_upscale/run.py diff --git a/server/operators/mflux_image_edit/manifest.json b/server/operators/mflux_image_edit/manifest.json new file mode 100644 index 0000000..8d0d8ce --- /dev/null +++ b/server/operators/mflux_image_edit/manifest.json @@ -0,0 +1,20 @@ +{ + "id": "mflux_image_edit", + "name": "Edit Image (local, Qwen)", + "category": "image-prep", + "description": "Image + instruction → edited image entirely on this Mac via mflux Qwen-Image-Edit (ungated/Apache-2.0). Free local alternative to fal_image_edit / nano-banana edit — 'remove the sticker', 'make it studio-lit on white', material/lighting changes. First run downloads weights.", + "accepts": ["image"], + "produces": ["image"], + "resources": "gpu", + "entry": "run.py", + "python": "/Users/m3ultra/Documents/MODELBEAST/venvs/mflux/bin/python", + "params_schema": { + "type": "object", + "properties": { + "prompt": {"type": "string", "default": "", "description": "Edit instruction (what to change)"}, + "steps": {"type": "integer", "default": 25, "minimum": 1, "maximum": 50, "description": "Inference steps"}, + "seed": {"type": "integer", "default": 42, "description": "Random seed"}, + "guidance": {"type": "number", "default": 4.0, "minimum": 0, "maximum": 10, "description": "Guidance scale"} + } + } +} diff --git a/server/operators/mflux_image_edit/run.py b/server/operators/mflux_image_edit/run.py new file mode 100644 index 0000000..db54f62 --- /dev/null +++ b/server/operators/mflux_image_edit/run.py @@ -0,0 +1,48 @@ +import argparse +import json +import subprocess +import sys +from pathlib import Path + +ap = argparse.ArgumentParser() +ap.add_argument("--input", action="append", default=[]) +ap.add_argument("--outdir", required=True) +ap.add_argument("--params", default="{}") +a = ap.parse_args() +p = json.loads(a.params) + +if not a.input: + print("ERROR: no input image") + sys.exit(1) +if not p.get("prompt"): + print("ERROR: prompt is required — describe the edit you want") + sys.exit(1) +cli = Path(sys.executable).parent / "mflux-generate-qwen-edit" +if not cli.exists(): + print(f"ERROR: {cli} missing. Run scripts/install_mflux.sh") + sys.exit(1) + +src = Path(a.input[0]) +outdir = Path(a.outdir) +out = outdir / f"{src.stem}_edited.png" +cmd = [str(cli), "--image-paths", str(src.resolve()), + "--prompt", p["prompt"], + "--steps", str(p.get("steps", 25)), + "--seed", str(p.get("seed", 42)), + "--guidance", str(p.get("guidance", 4.0)), + "--output", str(out.resolve())] + +print("+", " ".join(cmd), flush=True) +print("(first run downloads Qwen-Image-Edit weights)", flush=True) +res = subprocess.run(cmd, cwd=str(outdir), stdout=sys.stdout, stderr=subprocess.STDOUT) +if res.returncode != 0: + sys.exit(res.returncode) + +pngs = sorted(outdir.rglob("*.png")) +if not pngs: + print("ERROR: no edited image produced") + sys.exit(1) +img = out if out.exists() else pngs[-1] +(outdir / "result.json").write_text(json.dumps( + {"outputs": [{"path": img.name, "meta": {"tool": "qwen-image-edit"}}]})) +print(f"done: {img.name}", flush=True) diff --git a/server/operators/seedvr2_upscale/manifest.json b/server/operators/seedvr2_upscale/manifest.json new file mode 100644 index 0000000..d3e7e8e --- /dev/null +++ b/server/operators/seedvr2_upscale/manifest.json @@ -0,0 +1,20 @@ +{ + "id": "seedvr2_upscale", + "name": "Upscale (local, SeedVR2)", + "category": "image-prep", + "description": "Image → faithful upscale entirely on this Mac via mflux SeedVR2 (ByteDance, ungated/MIT). Free local alternative to the cloud fal_upscale. Sharpen thin/low-res inputs before mesh-gen or texture work. First run downloads weights.", + "accepts": ["image"], + "produces": ["image"], + "resources": "gpu", + "entry": "run.py", + "python": "/Users/m3ultra/Documents/MODELBEAST/venvs/mflux/bin/python", + "params_schema": { + "type": "object", + "properties": { + "resolution": {"type": "string", "default": "2x", "description": "Scale factor (\"2x\", \"4x\") or shortest-edge pixels (e.g. \"2048\")"}, + "softness": {"type": "number", "default": 0.0, "minimum": 0.0, "maximum": 1.0, "description": "Detail/denoise strength (0 = faithful, 1 = max)"}, + "seed": {"type": "integer", "default": 42, "description": "Random seed"}, + "quantize": {"type": "string", "enum": ["none", "8", "4"], "default": "none", "description": "Quantize to cut memory"} + } + } +} diff --git a/server/operators/seedvr2_upscale/run.py b/server/operators/seedvr2_upscale/run.py new file mode 100644 index 0000000..6f42ff9 --- /dev/null +++ b/server/operators/seedvr2_upscale/run.py @@ -0,0 +1,47 @@ +import argparse +import json +import subprocess +import sys +from pathlib import Path + +ap = argparse.ArgumentParser() +ap.add_argument("--input", action="append", default=[]) +ap.add_argument("--outdir", required=True) +ap.add_argument("--params", default="{}") +a = ap.parse_args() +p = json.loads(a.params) + +if not a.input: + print("ERROR: no input image") + sys.exit(1) +cli = Path(sys.executable).parent / "mflux-upscale-seedvr2" +if not cli.exists(): + print(f"ERROR: {cli} missing. Run scripts/install_mflux.sh") + sys.exit(1) + +src = Path(a.input[0]) +outdir = Path(a.outdir) +out = outdir / f"{src.stem}_upscaled.png" +cmd = [str(cli), "-i", str(src.resolve()), + "--resolution", str(p.get("resolution", "2x")), + "--softness", str(p.get("softness", 0.0)), + "--seed", str(p.get("seed", 42)), + "--output", str(out.resolve())] +quant = str(p.get("quantize", "none")) +if quant in ("4", "8"): + cmd += ["-q", quant] + +print("+", " ".join(cmd), flush=True) +print("(first run downloads SeedVR2 weights)", flush=True) +res = subprocess.run(cmd, cwd=str(outdir), stdout=sys.stdout, stderr=subprocess.STDOUT) +if res.returncode != 0: + sys.exit(res.returncode) + +pngs = sorted(outdir.rglob("*.png")) +if not pngs: + print("ERROR: no upscaled image produced") + sys.exit(1) +img = out if out.exists() else pngs[-1] +(outdir / "result.json").write_text(json.dumps( + {"outputs": [{"path": img.name, "meta": {"tool": "seedvr2", "resolution": p.get("resolution", "2x")}}]})) +print(f"done: {img.name}", flush=True)