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)