$ cat node-template.py

Image Upscale

// Upscales an image to higher resolution using Real-ESRGAN via a native GPU service. Accepts an image and a configurable upscale factor (2-4x). Outputs the upscaled image.

Process
Image
template.py
1import os2import sys3import json4import subprocess5import time6import traceback78try:9    import requests10except ImportError:11    subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])12    import requests1314NATIVE_IMAGE_UPSCALE_SERVICE_URL = os.getenv(15    "NATIVE_IMAGE_UPSCALE_SERVICE_URL", "http://native-image-upscale-service:8102"16)17_EMBLEMA_VERSION = os.getenv("EMBLEMA_VERSION", "dev")18NATIVE_IMAGE_UPSCALE_SERVICE_IMAGE = os.getenv(19    "NATIVE_IMAGE_UPSCALE_SERVICE_IMAGE",20    f"emblema/native-image-upscale-service:{_EMBLEMA_VERSION}",21)22HF_CACHE_HOST_PATH = os.getenv("HF_CACHE_HOST_PATH", "/root/.cache/huggingface")23CONTAINER_NAME = "native-image-upscale-service"24INPUT_DIR = "/data/input"25OUTPUT_DIR = "/data/output"262728def start_container():29    """Create and start native-image-upscale-service, removing any stale container first."""30    subprocess.run(31        ["docker", "rm", "-f", CONTAINER_NAME],32        capture_output=True, text=True33    )3435    hf_token = os.getenv("HUGGINGFACE_TOKEN", "")36    print(f"Creating container {CONTAINER_NAME}...", file=sys.stderr)37    run_cmd = [38        "docker", "run", "-d",39        "--name", CONTAINER_NAME,40        "--network", "emblema",41        "--gpus", "all",42        "-e", "PORT=8102",43        "-e", "DEVICE=cuda",44        "-e", f"HF_TOKEN={hf_token}",45        "-v", f"{HF_CACHE_HOST_PATH}:/root/.cache/huggingface",46        NATIVE_IMAGE_UPSCALE_SERVICE_IMAGE,47    ]48    result = subprocess.run(run_cmd, capture_output=True, text=True)49    if result.returncode != 0:50        print(f"docker run failed (exit {result.returncode}): {result.stderr}", file=sys.stderr)51        raise RuntimeError(f"Failed to start container: {result.stderr}")5253    # Poll health endpoint54    timeout = 18055    interval = 356    elapsed = 057    health_url = f"{NATIVE_IMAGE_UPSCALE_SERVICE_URL}/health"58    while elapsed < timeout:59        try:60            r = requests.get(health_url, timeout=5)61            if r.status_code == 200:62                print(f"Container healthy (waited {elapsed}s).", file=sys.stderr)63                return64        except requests.ConnectionError:65            pass66        time.sleep(interval)67        elapsed += interval6869    raise RuntimeError(f"Container did not become healthy within {timeout}s")707172def stop_container():73    """Remove the container."""74    try:75        subprocess.run(76            ["docker", "rm", "-f", CONTAINER_NAME],77            capture_output=True, text=True, timeout=3078        )79        print(f"Container {CONTAINER_NAME} removed.", file=sys.stderr)80    except Exception as e:81        print(f"Warning: failed to remove container: {e}", file=sys.stderr)828384def main():85    try:86        input_json = sys.stdin.read()87        execution_input = json.loads(input_json)88        inputs = execution_input.get("inputs", {})8990        image = inputs.get("image", "")91        upscale_factor = float(inputs.get("upscale_factor", 4))9293        if not image:94            raise ValueError("Image is required")95        if not (2 <= upscale_factor <= 4):96            raise ValueError(f"Upscale factor must be between 2 and 4, got {upscale_factor}")9798        local_path = os.path.join(INPUT_DIR, image)99        if not os.path.exists(local_path):100            raise FileNotFoundError(f"Input image not found: {local_path}")101102        os.makedirs(OUTPUT_DIR, exist_ok=True)103104        # Start the container105        start_container()106107        try:108            # Send image to service109            with open(local_path, "rb") as f:110                resp = requests.post(111                    f"{NATIVE_IMAGE_UPSCALE_SERVICE_URL}/upscale",112                    files={"image": (os.path.basename(local_path), f, "image/png")},113                    data={"upscale_factor": str(upscale_factor)},114                    timeout=600,115                )116117            if resp.status_code != 200:118                try:119                    error_detail = resp.json()120                except Exception:121                    error_detail = resp.text122                raise RuntimeError(123                    f"Upscale service returned {resp.status_code}: {error_detail}"124                )125126            # Save result127            out_filename = "upscaled_result.png"128            out_path = os.path.join(OUTPUT_DIR, out_filename)129            with open(out_path, "wb") as f:130                f.write(resp.content)131132            inference_time = resp.headers.get("X-Inference-Time-Ms", "unknown")133            output_size = resp.headers.get("X-Output-Size", "unknown")134            print(135                f"Upscaled: factor={upscale_factor}, output_size={output_size}, time={inference_time}ms",136                file=sys.stderr,137            )138139            output = {140                "image": out_filename,141            }142            print(json.dumps(output, indent=2))143144        finally:145            stop_container()146147    except Exception as e:148        error_output = {149            "error": str(e),150            "errorType": type(e).__name__,151            "traceback": traceback.format_exc(),152        }153        print(json.dumps(error_output), file=sys.stderr)154        sys.exit(1)155156157if __name__ == "__main__":158    main()