$ cat node-template.py

Image Remove Background Legacy

// Removes the background from an image using the RMBG-2.0 model. Outputs a PNG with alpha channel (transparency).

Process
Image
template.py
1import os2import sys3import json4import time5import traceback67try:8    import requests9except ImportError:10    import subprocess11    subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])12    import requests1314COMFYUI_API_URL = os.getenv("COMFYUI_API_URL", "http://192.168.1.39:8188")15INPUT_DIR = "/data/input"16OUTPUT_DIR = "/data/output"1718WORKFLOW = {19    "1": {20        "inputs": {21            "model": "RMBG-2.0",22            "sensitivity": 1,23            "process_res": 1024,24            "mask_blur": 0,25            "mask_offset": 0,26            "invert_output": True,27            "refine_foreground": False,28            "background": "Alpha",29            "background_color": "#222222",30            "image": ["7", 0],31        },32        "class_type": "RMBG",33        "_meta": {"title": "Remove Background (RMBG)"},34    },35    "6": {36        "inputs": {37            "filename_prefix": "removebg_emblema",38            "images": ["1", 0],39            "mask": ["1", 1],40        },41        "class_type": "SaveImageWithAlpha",42        "_meta": {"title": "Save Image With Alpha"},43    },44    "7": {45        "inputs": {"image": ""},46        "class_type": "LoadImage",47        "_meta": {"title": "Load Image"},48    },49}505152def upload_file_to_comfyui(local_path: str) -> str:53    """Upload a local image to ComfyUI and return the uploaded filename."""54    with open(local_path, "rb") as f:55        resp = requests.post(56            f"{COMFYUI_API_URL}/upload/image",57            files={"image": (os.path.basename(local_path), f, "image/png")},58            timeout=30,59        )60    resp.raise_for_status()61    data = resp.json()62    return data["name"]636465def build_workflow(image_name: str) -> dict:66    """Inject the uploaded image name into the workflow template."""67    import copy68    wf = copy.deepcopy(WORKFLOW)69    wf["7"]["inputs"]["image"] = image_name70    wf["6"]["inputs"]["filename_prefix"] = "removebg_emblema"71    return wf727374def submit_prompt(workflow: dict) -> str:75    """Submit workflow to ComfyUI and return prompt_id."""76    resp = requests.post(77        f"{COMFYUI_API_URL}/prompt",78        json={"prompt": workflow},79        timeout=30,80    )81    if resp.status_code != 200:82        try:83            error_detail = resp.json()84        except Exception:85            error_detail = resp.text86        raise RuntimeError(87            f"ComfyUI /prompt returned {resp.status_code}: {json.dumps(error_detail, indent=2) if isinstance(error_detail, dict) else error_detail}"88        )89    data = resp.json()9091    node_errors = data.get("node_errors", {})92    if node_errors:93        raise RuntimeError(94            f"ComfyUI workflow has node errors: {json.dumps(node_errors, indent=2)}"95        )9697    return data["prompt_id"]9899100def wait_for_result(prompt_id: str, timeout: int = 600, poll_interval: int = 2) -> dict:101    """Poll ComfyUI history until the prompt completes with outputs."""102    deadline = time.time() + timeout103    empty_complete_retries = 0104    max_empty_retries = 3105106    while time.time() < deadline:107        resp = requests.get(108            f"{COMFYUI_API_URL}/history/{prompt_id}",109            timeout=10,110        )111        resp.raise_for_status()112        history = resp.json()113114        if prompt_id in history:115            prompt_data = history[prompt_id]116            status = prompt_data.get("status", {})117118            if status.get("status_str") == "error":119                messages = status.get("messages", [])120                raise RuntimeError(121                    f"ComfyUI prompt failed: {json.dumps(messages, indent=2)}"122                )123124            if status.get("completed", False):125                if prompt_data.get("outputs"):126                    return prompt_data127128                empty_complete_retries += 1129                if empty_complete_retries >= max_empty_retries:130                    raise RuntimeError(131                        f"ComfyUI prompt completed but produced no outputs. "132                        f"This usually means a node failed silently (missing custom node or model). "133                        f"Status: {json.dumps(status, indent=2)}"134                    )135136        time.sleep(poll_interval)137138    raise TimeoutError(f"ComfyUI prompt {prompt_id} did not complete within {timeout}s")139140141def download_output_image(prompt_data: dict, output_dir: str) -> str:142    """Download the output PNG from ComfyUI."""143    outputs = prompt_data.get("outputs", {})144    for node_id, node_output in outputs.items():145        images = node_output.get("images", [])146        if images:147            img_info = images[0]148            filename = img_info["filename"]149            subfolder = img_info.get("subfolder", "")150            img_type = img_info.get("type", "output")151152            resp = requests.get(153                f"{COMFYUI_API_URL}/view",154                params={155                    "filename": filename,156                    "subfolder": subfolder,157                    "type": img_type,158                },159                timeout=30,160            )161            resp.raise_for_status()162163            out_filename = f"removebg_{filename}"164            out_path = os.path.join(output_dir, out_filename)165            with open(out_path, "wb") as f:166                f.write(resp.content)167168            return out_filename169170    raise RuntimeError(171        f"No output image found in ComfyUI response. Available outputs: {json.dumps(outputs, indent=2)}"172    )173174175def main():176    try:177        input_json = sys.stdin.read()178        execution_input = json.loads(input_json)179        inputs = execution_input.get("inputs", {})180181        image = inputs.get("image", "")182        if not image:183            raise ValueError("Input image is required")184185        os.makedirs(OUTPUT_DIR, exist_ok=True)186187        # Upload input image to ComfyUI188        local_path = os.path.join(INPUT_DIR, image)189        if not os.path.exists(local_path):190            raise FileNotFoundError(f"Input image not found: {local_path}")191        uploaded_name = upload_file_to_comfyui(local_path)192193        # Build and submit workflow194        workflow = build_workflow(uploaded_name)195        prompt_id = submit_prompt(workflow)196197        # Wait for completion and download result198        prompt_data = wait_for_result(prompt_id)199        out_filename = download_output_image(prompt_data, OUTPUT_DIR)200201        # Log metadata to stderr202        print(f"prompt_id={prompt_id}", file=sys.stderr)203204        # Flat output — keys match OUTPUT_SCHEMA205        output = {206            "image": out_filename,207        }208        print(json.dumps(output, indent=2))209210    except Exception as e:211        error_output = {212            "error": str(e),213            "errorType": type(e).__name__,214            "traceback": traceback.format_exc(),215        }216        print(json.dumps(error_output), file=sys.stderr)217        sys.exit(1)218219220if __name__ == "__main__":221    main()