---
name: comfyui_build_img2img_workflow
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_build_img2img_workflow(ckpt_name: str, init_image: str, positive: str, negative: str = \"\", *, denoise: float = 0.6, steps: int = 20, cfg: float = 7.0, seed: int = 0, sampler_name: str = \"euler\", scheduler: str = \"normal\") -> dict"
description: "Construye el dict de un workflow ComfyUI img2img en API format para SD1.5/SDXL: CheckpointLoaderSimple + LoadImage -> VAEEncode -> KSampler (con denoise < 1.0 para conservar la imagen base) -> VAEDecode -> SaveImage. Pura, sin red ni I/O. Hermana de comfyui_build_txt2img_workflow."
tags: [comfyui, ml, image-generation, img2img, stable-diffusion, workflow]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: ckpt_name
    desc: "Nombre del checkpoint tal como lo ve el servidor ComfyUI (ej. 'IMG_dreamshaper_8.safetensors'). Debe estar en la lista de CheckpointLoaderSimple de comfyui_object_info."
  - name: init_image
    desc: "Nombre del archivo de imagen base dentro de la carpeta input/ del servidor ComfyUI; lo carga el nodo LoadImage."
  - name: positive
    desc: "Prompt positivo: lo que se quiere ver en la imagen."
  - name: negative
    desc: "Prompt negativo: lo que se quiere evitar. Por defecto cadena vacia."
  - name: denoise
    desc: "Fuerza de denoising del KSampler (0.0 = identica a la base, 1.0 = ignora la base). Tipico 0.4-0.7 para img2img. keyword-only."
  - name: steps
    desc: "Pasos de sampling del KSampler. keyword-only."
  - name: cfg
    desc: "Classifier-free guidance scale. keyword-only."
  - name: seed
    desc: "Semilla del KSampler. 0 es determinista; cambiar para variar. keyword-only."
  - name: sampler_name
    desc: "Nombre del sampler (ej. 'euler', 'dpmpp_2m'). keyword-only."
  - name: scheduler
    desc: "Scheduler del sampler (ej. 'normal', 'karras'). keyword-only."
output: "dict en API format con node_ids como claves (CheckpointLoaderSimple '4', LoadImage '10', VAEEncode '11', CLIPTextEncode '6'/'7', KSampler '3', VAEDecode '8', SaveImage '9'). Listo para comfyui_submit_workflow."
tested: true
tests: ["usa VAEEncode/LoadImage y no EmptyLatentImage", "denoise e init_image reflejados", "determinismo: misma entrada -> mismo dict (builder puro)"]
test_file_path: "python/functions/ml/tests/test_comfyui_build_img2img_workflow.py"
file_path: "python/functions/ml/comfyui_build_img2img_workflow.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_build_img2img_workflow import comfyui_build_img2img_workflow

wf = comfyui_build_img2img_workflow(
    ckpt_name="IMG_dreamshaper_8.safetensors",
    init_image="cabin.png",          # archivo en el input/ de ComfyUI
    positive="a cozy cabin in the woods, golden hour",
    negative="blurry, low quality",
    denoise=0.55,                     # conserva ~la mitad de la imagen base
    seed=42,
)
# wf["11"]["class_type"] == "VAEEncode"
# wf["3"]["inputs"]["latent_image"] == ["11", 0]   # KSampler parte del latente de la imagen
# wf["3"]["inputs"]["denoise"] == 0.55
```

El bloque de arriba se lanza con el python del venv (`python/.venv/bin/python3`). Nota: `./fn run` directo no aplica a este builder porque su firma usa `*` (keyword-only) y el generador de runner de `fn run` no lo soporta — igual que en `comfyui_build_txt2img_workflow`. Usa el import de arriba o un heredoc.

## Cuando usarla

Cuando quieras transformar una imagen existente con un prompt (variaciones,
restyling, refine) en lugar de generar desde ruido. Sube primero la imagen base
al `input/` del servidor (o cargala por la UI) y pasa su nombre en `init_image`.
Para generar desde cero usa `comfyui_build_txt2img_workflow`; para ampliar una
imagen usa `comfyui_build_upscale_workflow`.

## Gotchas

- Es API format (nodos numerados), NO el formato de la UI de ComfyUI. Es lo que
  acepta POST /prompt.
- `init_image` debe existir en la carpeta `input/` del servidor (no es un path
  local arbitrario). Subela antes con la UI o copiala a `~/ComfyUI/input/`.
- `denoise` controla cuanto se conserva de la base: cerca de 1.0 ignora la
  imagen (casi txt2img); cerca de 0.0 apenas la cambia. 0.4-0.7 es el rango util.
- Asume que el checkpoint trae VAE embebido (VAEEncode/VAEDecode usan `["4", 2]`).
  Para un VAE externo cambia esas conexiones.
- Es pura: NO valida que `ckpt_name`/`init_image` existan en el servidor. Si no
  existen, ComfyUI rechaza el workflow con HTTP 400 al enviarlo. Valida antes con
  `comfyui_validate_workflow`.
