From ab27c253c5d6144b42397b7f3a88d3da9c0e53a6 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Sat, 27 Jun 2026 00:00:38 +0200 Subject: [PATCH] fix(gamedev): card_art hires roto (UltimateSDUpscale exige batch_size) + INDEX conteo gamedev 10->20 El nodo UltimateSDUpscale declara batch_size como input requerido en /object_info; comfyui_build_hires_fix_workflow y comfyui_inject_hires_fix no lo proveian, por lo que card_art con hires=True fallaba en runtime. Se anade batch_size: 1 a ambos constructores + guards de regresion en los tests (card_art golden hires, builder e inject). Verificado con una generacion real en ComfyUI (carta 768x1152, sin node_errors, prompt_id 4033fb0b). Bump de version 1.0.0->1.0.1 en ambos .md con growth log y gotcha. INDEX.md: la fila gamedev decia count=10; el cluster de assets 2D documentado en gamedev-2d.md tiene 20 funciones (15 builders tag gamedev-2d + 5 de apoyo). Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/capabilities/INDEX.md | 2 +- .../ml/comfyui_build_card_art_workflow_test.py | 4 ++++ .../ml/comfyui_build_hires_fix_workflow.md | 16 ++++++++++++++-- .../ml/comfyui_build_hires_fix_workflow.py | 1 + python/functions/ml/comfyui_inject_hires_fix.md | 13 +++++++++++-- python/functions/ml/comfyui_inject_hires_fix.py | 1 + .../test_comfyui_build_hires_fix_workflow.py | 9 +++++++++ .../ml/tests/test_comfyui_inject_hires_fix.py | 3 +++ 8 files changed, 44 insertions(+), 5 deletions(-) diff --git a/docs/capabilities/INDEX.md b/docs/capabilities/INDEX.md index b5934960..7c0a68c4 100644 --- a/docs/capabilities/INDEX.md +++ b/docs/capabilities/INDEX.md @@ -14,7 +14,7 @@ Indice de grupos de capacidades del registry. Cada grupo agrupa >=3 funciones qu | Grupo | N | Que cubre | |---|---|---| -| [gamedev](gamedev-2d.md) | 10 | Assets 2D para Godot: builders de workflow ComfyUI (pixelart/seamless/iso/sprite/VFX, tag `gamedev-2d`) + post-proceso (pixelize, luma->alpha) + puente de assets a Godot 4 (.import + reimport headless) | +| [gamedev](gamedev-2d.md) | 20 | Assets 2D para Godot: 15 builders de workflow ComfyUI (pixelart/seamless/iso/sprite/topdown/card/enemy/prop/VFX..., tag `gamedev-2d`) + 5 de apoyo: post-proceso (pixelize, luma->alpha) + puente de assets a Godot 4 (.import + reimport headless) | | [registry](registry.md) | 17 | Auditoria y monitorizacion del propio registry: copied-code, uses-functions, unused, proposals, telemetria | | [systemd](systemd.md) | 14 | Generar, instalar, restart y status de unit files systemd via SSH (deploys a VPS) | | [ssh](ssh.md) | 19 | Operar hosts remotos via SSH: config, conn, ejecutar comandos, port-forward, deploys con SCP/rsync | diff --git a/python/functions/ml/comfyui_build_card_art_workflow_test.py b/python/functions/ml/comfyui_build_card_art_workflow_test.py index 24763ddc..0e84c8da 100644 --- a/python/functions/ml/comfyui_build_card_art_workflow_test.py +++ b/python/functions/ml/comfyui_build_card_art_workflow_test.py @@ -54,6 +54,10 @@ def test_golden_hires_recipe(): assert latent["width"] == 512 assert latent["height"] == 768 assert latent["width"] < latent["height"] + # Regresion: UltimateSDUpscale exige batch_size (input requerido segun + # /object_info). Sin el, el submit con hires=True fallaba con node_errors. + usd = _by_class(wf, "UltimateSDUpscale")[0]["inputs"] + assert usd["batch_size"] == 1 def test_edge_no_hires_plain_txt2img(): diff --git a/python/functions/ml/comfyui_build_hires_fix_workflow.md b/python/functions/ml/comfyui_build_hires_fix_workflow.md index af2d5f34..a4e1109f 100644 --- a/python/functions/ml/comfyui_build_hires_fix_workflow.md +++ b/python/functions/ml/comfyui_build_hires_fix_workflow.md @@ -3,7 +3,7 @@ name: comfyui_build_hires_fix_workflow kind: function lang: py domain: ml -version: "1.0.0" +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." @@ -47,7 +47,7 @@ params: 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", "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)"] +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" --- @@ -102,3 +102,15 @@ queda corto porque no inventa detalle nuevo. Después: `comfyui_submit_workflow` 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). diff --git a/python/functions/ml/comfyui_build_hires_fix_workflow.py b/python/functions/ml/comfyui_build_hires_fix_workflow.py index 26b63eae..243b6da9 100644 --- a/python/functions/ml/comfyui_build_hires_fix_workflow.py +++ b/python/functions/ml/comfyui_build_hires_fix_workflow.py @@ -143,6 +143,7 @@ def comfyui_build_hires_fix_workflow( "seam_fix_padding": 16, "force_uniform_tiles": True, "tiled_decode": False, + "batch_size": 1, }, }, "9": { diff --git a/python/functions/ml/comfyui_inject_hires_fix.md b/python/functions/ml/comfyui_inject_hires_fix.md index 231eebb1..715f7137 100644 --- a/python/functions/ml/comfyui_inject_hires_fix.md +++ b/python/functions/ml/comfyui_inject_hires_fix.md @@ -3,7 +3,7 @@ name: comfyui_inject_hires_fix kind: function lang: py domain: ml -version: "1.0.0" +version: "1.0.1" purity: pure signature: "def comfyui_inject_hires_fix(workflow: dict, *, 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) -> dict" description: "Inyecta una segunda pasada hires-fix en un workflow ComfyUI ya construido (API format) que termina en VAEDecode -> SaveImage. Anade UpscaleModelLoader + UltimateSDUpscale (re-difusion por tiles) conectados a la imagen del VAEDecode y al model/vae del CheckpointLoaderSimple, y repunta el SaveImage a la imagen ampliada. Version encadenable-sobre-dict de comfyui_build_hires_fix_workflow. Pura: no muta el dict de entrada (copia profunda)." @@ -39,7 +39,7 @@ params: desc: "Alto de tile de UltimateSDUpscale (px). keyword-only." output: "copia del workflow con UpscaleModelLoader + UltimateSDUpscale anadidos (node_ids = max id numerico + 1 y + 2) y el SaveImage repuntado a la salida [ultimatesdupscale_id, 0]. Si no habia SaveImage, se anade uno con filename_prefix 'hires'." tested: true -tests: ["no muta el dict de entrada (pureza)", "inserta UltimateSDUpscale y UpscaleModelLoader", "repunta el SaveImage al UltimateSDUpscale", "params reflejados (upscale_by/denoise/seed)", "lanza ValueError si falta VAEDecode"] +tests: ["no muta el dict de entrada (pureza)", "inserta UltimateSDUpscale y UpscaleModelLoader", "repunta el SaveImage al UltimateSDUpscale", "params reflejados (upscale_by/denoise/seed) + batch_size", "lanza ValueError si falta VAEDecode"] test_file_path: "python/functions/ml/tests/test_comfyui_inject_hires_fix.py" file_path: "python/functions/ml/comfyui_inject_hires_fix.py" --- @@ -81,3 +81,12 @@ VAEDecode -> SaveImage. Una sola llamada anade la segunda pasada completa. Para grafos multi-salida construye con un builder dedicado. - El nuevo node_id es `max(ids numericos) + 1` (y +2). Si tu workflow usa ids no numericos, el contador cae a `len(workflow) + 1`. +- El nodo `UltimateSDUpscale` declara `batch_size` como input **requerido** en + `/object_info`; la inyección lo fija a `1`. Sin él, el submit pasaba la + validación de POST pero el grafo fallaba en runtime por input faltante. + +## Capability growth log + +- v1.0.1 (2026-06-27) — bugfix paralelo al de `comfyui_build_hires_fix_workflow`: + el nodo `UltimateSDUpscale` exige `batch_size` (input requerido en `/object_info`); + se añade `batch_size: 1` al nodo inyectado para que el workflow no falle en runtime. diff --git a/python/functions/ml/comfyui_inject_hires_fix.py b/python/functions/ml/comfyui_inject_hires_fix.py index 93350fc7..4d4cc0c8 100644 --- a/python/functions/ml/comfyui_inject_hires_fix.py +++ b/python/functions/ml/comfyui_inject_hires_fix.py @@ -149,6 +149,7 @@ def comfyui_inject_hires_fix( "seam_fix_padding": 16, "force_uniform_tiles": True, "tiled_decode": False, + "batch_size": 1, }, } diff --git a/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py b/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py index e09f3752..9cc4286d 100644 --- a/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py @@ -22,6 +22,15 @@ def test_base_ksampler_and_ultimate_upscale_present(): assert wf["9"]["inputs"]["images"] == ["12", 0] +def test_ultimate_upscale_provee_batch_size(): + # /object_info marca batch_size como input REQUERIDO de UltimateSDUpscale. + # Sin el, el submit fallaba con node_errors. Regresion guard. + wf = comfyui_build_hires_fix_workflow( + ckpt_name="dreamshaper_8.safetensors", positive="x", + ) + assert wf["12"]["inputs"]["batch_size"] == 1 + + def test_second_pass_denoise_is_partial(): wf = comfyui_build_hires_fix_workflow( ckpt_name="dreamshaper_8.safetensors", positive="x", denoise=0.4, diff --git a/python/functions/ml/tests/test_comfyui_inject_hires_fix.py b/python/functions/ml/tests/test_comfyui_inject_hires_fix.py index 6b2fd385..bc35f9c7 100644 --- a/python/functions/ml/tests/test_comfyui_inject_hires_fix.py +++ b/python/functions/ml/tests/test_comfyui_inject_hires_fix.py @@ -60,6 +60,9 @@ def test_params_reflejados(): assert up_in["mode_type"] == "Linear" assert up_in["force_uniform_tiles"] is True assert up_in["tiled_decode"] is False + # /object_info marca batch_size como input REQUERIDO de UltimateSDUpscale. + # Sin el, el submit fallaba con node_errors. Regresion guard. + assert up_in["batch_size"] == 1 def test_lanza_valueerror_sin_vaedecode():