---
name: comfyui_build_hires_fix_workflow
kind: function
lang: py
domain: ml
version: "1.0.1"
purity: pure
signature: "def comfyui_build_hires_fix_workflow(ckpt_name: str, positive: str, negative: str = \"\", *, first_pass: tuple[int, int] = (768, 768), upscale_by: float = 1.5, denoise: float = 0.4, steps: int = 20, cfg: float = 7.0, seed: int = 0, upscale_model: str = \"4x_foolhardy_Remacri.pth\", sampler_name: str = \"euler\", scheduler: str = \"normal\", tile_width: int = 512, tile_height: int = 512, filename_prefix: str = \"hires\") -> dict"
description: "Construye un workflow ComfyUI de hires-fix de 2 pasadas en API format: genera una imagen base pequena (KSampler) y la amplia re-difundiendola por tiles con UltimateSDUpscale + un modelo de upscale (Remacri), anadiendo detalle real a alta resolucion. UltimateSDUpscale es la segunda pasada de muestreo (recibe model/positive/negative/vae). Distinto de comfyui_build_upscale_workflow, que es ESRGAN puro sin re-difusion. Class_types verificados en /object_info. Pura, sin red ni I/O."
tags: [comfyui, ml, hires-fix, ultimatesdupscale, upscale, workflow]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: ckpt_name
    desc: "Checkpoint tal como lo ve el servidor (CheckpointLoaderSimple)."
  - name: positive
    desc: "Prompt positivo (se usa en la base y en la re-difusion tiled)."
  - name: negative
    desc: "Prompt negativo. Por defecto ''."
  - name: first_pass
    desc: "(ancho, alto) en px de la pasada base (latente pequeno y rapido). Por defecto (768, 768). keyword-only."
  - name: upscale_by
    desc: "Factor de ampliacion de UltimateSDUpscale sobre la imagen base (1.5 -> 768 pasa a 1152). keyword-only."
  - name: denoise
    desc: "Fuerza de re-difusion de la segunda pasada (0.4 por defecto). <1 conserva la composicion base y solo anade detalle; 1.0 la re-generaria entera. keyword-only."
  - name: steps
    desc: "Pasos de sampling (ambas pasadas). keyword-only."
  - name: cfg
    desc: "Classifier-free guidance (ambas pasadas). keyword-only."
  - name: seed
    desc: "Semilla de la pasada base (UltimateSDUpscale usa la misma). keyword-only."
  - name: upscale_model
    desc: "Modelo de upscale en models/upscale_models/ que usa UltimateSDUpscale para escalar antes de re-difundir (ej. '4x_foolhardy_Remacri.pth'). keyword-only."
  - name: sampler_name
    desc: "Sampler (ambas pasadas). keyword-only."
  - name: scheduler
    desc: "Scheduler (ambas pasadas). keyword-only."
  - name: tile_width
    desc: "Ancho de tile de UltimateSDUpscale (px). Tiles mas pequenos = menos VRAM, mas costuras. keyword-only."
  - name: tile_height
    desc: "Alto de tile de UltimateSDUpscale (px). keyword-only."
  - name: filename_prefix
    desc: "Prefijo del PNG final que escribe SaveImage. keyword-only."
output: "dict en API format listo para comfyui_submit_workflow. node_ids: '4' CheckpointLoaderSimple, '5' EmptyLatentImage, '6'/'7' CLIPTextEncode, '3' KSampler (base), '8' VAEDecode, '11' UpscaleModelLoader, '12' UltimateSDUpscale, '9' SaveImage."
tested: true
tests: ["cadena base (KSampler) + UltimateSDUpscale + SaveImage", "UltimateSDUpscale provee batch_size (input requerido)", "denoise de la 2a pasada <1 (re-difusion parcial)", "first_pass refleja width/height en EmptyLatentImage", "upscale_model llega a UpscaleModelLoader", "determinismo: misma entrada -> mismo dict (builder puro)"]
test_file_path: "python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py"
file_path: "python/functions/ml/comfyui_build_hires_fix_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_hires_fix_workflow import comfyui_build_hires_fix_workflow

wf = comfyui_build_hires_fix_workflow(
    ckpt_name="IMG_dreamshaper_8.safetensors",
    positive="a fox in a forest, intricate detail, sharp focus",
    negative="blurry, low quality",
    first_pass=(768, 768),
    upscale_by=1.5,
    denoise=0.4,
    seed=42,
)
# wf["3"]["class_type"] == "KSampler"             # pasada base
# wf["12"]["class_type"] == "UltimateSDUpscale"   # pasada de detalle (re-difusion)
# wf["12"]["inputs"]["denoise"] == 0.4            # <1 = solo anade detalle
# wf["11"]["inputs"]["model_name"] == "4x_foolhardy_Remacri.pth"
```

O lanzable directo con: `./fn run comfyui_build_hires_fix_workflow` (imprime el JSON del workflow de ejemplo).

## Cuando usarla

Cuando una imagen a baja resolución se ve plana o sin detalle y quieres una
versión grande y nítida que el modelo "redibuja" en alta (no un simple escalado).
Es el "hires fix" idiomático: genera la base pequeña y rápida, luego añade detalle
real al ampliar. Úsala cuando `comfyui_build_upscale_workflow` (ESRGAN puro) se
queda corto porque no inventa detalle nuevo. Después: `comfyui_submit_workflow`
→ `comfyui_wait_result` → `comfyui_fetch_output_image`.

## Gotchas

- Es API format (nodos numerados), NO el formato de la UI.
- Requiere el custom node **UltimateSDUpscale** (`comfyui_ultimatesdupscale`). Si
  el server responde HTTP 400 "node type not found: UltimateSDUpscale", el custom
  node no está cargado.
- El `upscale_model` debe existir en `models/upscale_models/` (aquí
  `4x_foolhardy_Remacri.pth`). Sin él, el server rechaza el workflow al encolar.
- **2 etapas de muestreo, 1 KSampler explícito**: UltimateSDUpscale re-samplea
  cada tile internamente (por eso recibe `model`/`positive`/`negative`/`vae`), así
  que el grafo tiene el KSampler base + el UltimateSDUpscale, no dos KSampler.
- `denoise` de la 2ª pasada controla cuánto cambia: 0.3–0.45 añade detalle sin
  alterar la composición; >0.6 puede deformar caras o introducir artefactos.
- `upscale_by` alto + `tile_width/height` grandes = más VRAM. En 8 GB conviene
  tiles de 512 y `upscale_by` 1.5–2.0.
- Coste real: la 2ª pasada re-difunde N tiles, es bastante más lenta que un upscale
  ESRGAN puro. Para solo agrandar sin re-difusión usa `comfyui_build_upscale_workflow`.
- El nodo `UltimateSDUpscale` declara `batch_size` como input **requerido** en
  `/object_info` (esta versión de ComfyUI). El builder lo fija a `1`; sin él el
  server aceptaba el POST pero el grafo fallaba en runtime (input faltante). Si
  cambia la firma del custom node, verifica con
  `curl /object_info/UltimateSDUpscale`.

## Capability growth log

- v1.0.1 (2026-06-27) — bugfix: el nodo `UltimateSDUpscale` exige `batch_size`
  (input requerido en `/object_info`); se añade `batch_size: 1`. Sin él, los
  workflows con hires fallaban en runtime (afectaba a `comfyui_build_card_art_workflow`,
  único consumidor). Verificado con submit real a ComfyUI (768×1152, sin node_errors).
