$ cat node-template.py

I

Image Edit

// Edits images using up to 10 reference images and a text prompt. Supports configurable aspect ratio, megapixel output, and reproducible seeds.

Process
Image
template.py
1import os2import sys3import json4import random5import traceback67from gais import Gais89INPUT_DIR = "/data/input"10OUTPUT_DIR = "/data/output"111213def main():14    try:15        input_json = sys.stdin.read()16        execution_input = json.loads(input_json)17        inputs = execution_input.get("inputs", {})18        service_defaults = execution_input.get("service_defaults", {})1920        images = inputs.get("images", [])21        prompt = inputs.get("prompt", "")22        aspect_ratio = float(inputs.get("aspect_ratio", 1.667) or 1.667)23        megapixel = float(inputs.get("megapixel", 1.0) or 1.0)2425        # Seed mode handling26        seed_mode = inputs.get("seed_mode", "random")27        seed_in = inputs.get("seed", -1)28        seed_input = int(seed_in) if seed_in not in (None, "") else -12930        if seed_mode == "fixed" and seed_input >= 0:31            seed_value = seed_input32        else:33            seed_value = random.randint(0, 2**31 - 1)3435        # Normalize images to a list (single edge gives a string, array edge gives a list)36        if isinstance(images, str):37            images = [images]3839        if not prompt:40            raise ValueError("Prompt is required")41        if not (0.25 <= aspect_ratio <= 4.0):42            raise ValueError(f"Aspect ratio must be between 0.25 and 4.0, got {aspect_ratio}")43        if not (0.25 <= megapixel <= 4.0):44            raise ValueError(f"Megapixel must be between 0.25 and 4.0, got {megapixel}")45        if not images or len(images) == 0:46            raise ValueError("At least one input image is required")47        if len(images) > 10:48            raise ValueError("Maximum of 10 input images supported")4950        # Validate all input images exist and collect paths51        image_paths = []52        for img_filename in images:53            local_path = os.path.join(INPUT_DIR, img_filename)54            if not os.path.exists(local_path):55                raise FileNotFoundError(f"Input image not found: {local_path}")56            image_paths.append(local_path)5758        os.makedirs(OUTPUT_DIR, exist_ok=True)5960        print(61            f"Requesting edit: images={len(image_paths)}, aspect_ratio={aspect_ratio}, megapixel={megapixel}, seed={seed_value}",62            file=sys.stderr,63        )6465        result = Gais.image.edit(66            images=image_paths,67            prompt=prompt,68            aspect_ratio=aspect_ratio,69            megapixel=megapixel,70            seed_mode=seed_mode,71            seed=seed_value,72        )7374        # Save result75        out_filename = "edited_image.png"76        out_path = os.path.join(OUTPUT_DIR, out_filename)77        with open(out_path, "wb") as f:78            f.write(result.content)7980        seed_used = result.metadata.get("seed", str(seed_value))81        inference_time = result.metadata.get("inference_time_ms", "unknown")82        output_size = result.metadata.get("output_size", "unknown")83        print(84            f"Edited: seed={seed_used}, time={inference_time}ms, size={output_size}, images={len(image_paths)}",85            file=sys.stderr,86        )8788        # Probe output dimensions and emit aspect_ratio + resolution so89        # downstream nodes can chain.90        try:91            from PIL import Image92            with Image.open(out_path) as _im:93                _w, _h = _im.size94        except Exception:95            _w, _h = 0, 09697        # Flat output — keys match OUTPUT_SCHEMA98        output = {99            "image": out_filename,100            "aspect_ratio": round(_w / _h, 4) if _h else 0.0,101            "resolution": f"{_w}x{_h}",102        }103        print(json.dumps(output, indent=2))104105    except Exception as e:106        error_output = {107            "error": str(e),108            "errorType": type(e).__name__,109            "traceback": traceback.format_exc(),110        }111        print(json.dumps(error_output), file=sys.stderr)112        sys.exit(1)113114115if __name__ == "__main__":116    main()

$ git log --oneline

v1.8.0
HEAD
2026-08-18
v1.6.02026-05-07
v1.4.12026-04-28
v1.2.02026-03-29
v1.1.02026-03-20