---
name: comfyui_build_inpaint_workflow
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_build_inpaint_workflow(ckpt_name: str, image: str, mask: str, positive: str, negative: str = \"\", *, denoise: float = 1.0, 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 inpaint en API format para SD1.5/SDXL: CheckpointLoaderSimple + LoadImage (base) + LoadImageMask (mascara) -> VAEEncodeForInpaint -> KSampler -> VAEDecode -> SaveImage. Regenera solo la zona enmascarada conservando el resto. Pura, sin red ni I/O. Hermana de comfyui_build_txt2img_workflow."
tags: [comfyui, ml, image-generation, inpaint, 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: image
    desc: "Nombre del archivo de la imagen base dentro de la carpeta input/ del servidor ComfyUI; lo carga el nodo LoadImage."
  - name: mask
    desc: "Nombre del archivo de la mascara dentro de input/ del servidor; lo carga LoadImageMask. Las zonas blancas se regeneran."
  - name: positive
    desc: "Prompt positivo: lo que se quiere ver en la zona enmascarada."
  - name: negative
    desc: "Prompt negativo: lo que se quiere evitar. Por defecto cadena vacia."
  - name: denoise
    desc: "Fuerza de denoising del KSampler (1.0 regenera por completo la zona enmascarada; <1.0 conserva parte de la base). 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', LoadImageMask '12', VAEEncodeForInpaint '11', CLIPTextEncode '6'/'7', KSampler '3', VAEDecode '8', SaveImage '9'). Listo para comfyui_submit_workflow."
tested: true
tests: ["usa LoadImageMask+VAEEncodeForInpaint", "imagen base, mascara, seed y denoise reflejados", "determinismo: misma entrada -> mismo dict (builder puro)"]
test_file_path: "python/functions/ml/tests/test_comfyui_build_inpaint_workflow.py"
file_path: "python/functions/ml/comfyui_build_inpaint_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_inpaint_workflow import comfyui_build_inpaint_workflow

wf = comfyui_build_inpaint_workflow(
    ckpt_name="IMG_dreamshaper_8.safetensors",
    image="room.png",          # imagen base en el input/ de ComfyUI
    mask="room_mask.png",      # mascara: blanco = zona a regenerar
    positive="a vase of red flowers on the table, sharp focus",
    negative="blurry, low quality",
    denoise=1.0,
    seed=42,
)
# wf["11"]["class_type"] == "VAEEncodeForInpaint"
# wf["11"]["inputs"]["mask"] == ["12", 0]      # mascara desde LoadImageMask
# wf["3"]["inputs"]["latent_image"] == ["11", 0]  # KSampler parte del latente inpaint
```

El bloque se lanza con el python del venv (`python/.venv/bin/python3`). `./fn run`
directo no aplica a este builder porque su firma usa `*` (keyword-only); usa el
import de arriba o un heredoc.

## Cuando usarla

Cuando quieras reemplazar solo una parte de una imagen (quitar un objeto, cambiar
un detalle, rellenar una zona) conservando el resto intacto. Sube la imagen base
y la mascara al `input/` del servidor y pasa sus nombres. Para transformar la
imagen entera usa `comfyui_build_img2img_workflow`; para generar desde cero
`comfyui_build_txt2img_workflow`.

## Gotchas

- Es API format (nodos numerados), NO el formato de la UI de ComfyUI. Es lo que
  acepta POST /prompt.
- `image` y `mask` deben existir en la carpeta `input/` del servidor (no son
  paths locales arbitrarios). Subelos antes con la UI o copialos a `~/ComfyUI/input/`.
- `LoadImageMask` lee el canal `red` por defecto: la mascara debe tener la zona a
  regenerar en blanco. Si tu mascara usa el canal alpha, cambia `channel` en el
  nodo '12' tras construir.
- `VAEEncodeForInpaint` usa `grow_mask_by: 6` (suaviza el borde de la mascara).
  Ajustalo en el nodo '11' si necesitas un borde mas duro o mas difuso.
- Asume que el checkpoint trae VAE embebido (VAEEncodeForInpaint/VAEDecode usan
  `["4", 2]`). Para un VAE externo cambia esas conexiones.
- Es pura: NO valida que `ckpt_name`/`image`/`mask` existan en el servidor.
  Valida antes con `comfyui_validate_workflow`.
