feat(ml): mixer de capacidades comfyui (compose + generate_mixed_oneshot + inject controlnet/ipadapter)
Mezclador del grupo comfyui-skill que promueve a una sola llamada la secuencia base -> compose -> submit -> wait -> fetch -> judge (issue 0087): - comfyui_compose_capabilities_py_ml (PURA): aplica en orden las capacidades activadas (loras, controlnet, ipadapter, facedetailer, hires) sobre un workflow base, sin mutar la entrada. - comfyui_generate_mixed_oneshot_py_pipelines: one-shot que resuelve el base (skill/txt2img/dict), compone, encola, espera, descarga el PNG y lo puntua con el panel comfyui-judge. - comfyui_inject_controlnet_py_ml, comfyui_inject_ipadapter_py_ml: inyectores encadenables que consume el compose. - Tests (24 passed) + pagina madre docs/capabilities/comfyui-skill.md. Prueba real en GPU: txt2img dreamshaper_8 + 2 LoRAs (3d_render_redmond + detail_tweaker) + FaceDetailer -> imagen 512x512 en ~24s, juez verdict 'good' (score 4.69, votos aesthetic+clip good; voto llm degradado por rate-limit 429). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
---
|
||||
name: comfyui_compose_capabilities
|
||||
kind: function
|
||||
lang: py
|
||||
domain: ml
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "def comfyui_compose_capabilities(base_workflow: dict, *, loras: list[dict] | None = None, controlnet: dict | None = None, ipadapter: dict | None = None, hires: dict | None = None, facedetailer: dict | None = None) -> dict"
|
||||
description: "Mezclador de capacidades ComfyUI: toma un workflow base en API format (skill o txt2img) y aplica EN ORDEN las capacidades activadas (cada arg None = desactivada), componiendo los inyectores/builders encadenables del registry: loras (inject_multi_lora) -> controlnet (inject_controlnet) -> ipadapter (inject_ipadapter) -> facedetailer (build_facedetailer_workflow) -> hires (inject_hires_fix), reconectando MODEL/CLIP/positive/IMAGE. Cada capacidad es opcional e independiente; sin ninguna devuelve el base intacto. Pura: no muta el dict de entrada."
|
||||
tags: [comfyui, comfyui-skill, ml, mixer, lora, controlnet, ipadapter, facedetailer, hires, workflow]
|
||||
uses_functions: [comfyui_inject_multi_lora_py_ml, comfyui_inject_controlnet_py_ml, comfyui_inject_ipadapter_py_ml, comfyui_build_facedetailer_workflow_py_ml, comfyui_inject_hires_fix_py_ml]
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: []
|
||||
params:
|
||||
- name: base_workflow
|
||||
desc: "dict en API format (salida de comfyui_build_skill_workflow o comfyui_build_txt2img_workflow). No se muta; se devuelve una copia."
|
||||
- name: loras
|
||||
desc: "Lista de dicts {name, strength_model?, strength_clip?} para inject_multi_lora. None o vacia = sin LoRAs. keyword-only."
|
||||
- name: controlnet
|
||||
desc: "Dict para inject_controlnet: {control_image (obligatoria), cn_name (obligatoria), strength?, positive_node?}. None = sin ControlNet. keyword-only."
|
||||
- name: ipadapter
|
||||
desc: "Dict para inject_ipadapter: {ref_image (obligatoria), mode ('style'|'faceid'), weight?, ...}. None = sin IPAdapter. keyword-only."
|
||||
- name: hires
|
||||
desc: "Dict de kwargs para inject_hires_fix (upscale_by, denoise, steps, cfg, seed, upscale_model, ...). {} = hires con defaults. None = sin hires. keyword-only."
|
||||
- name: facedetailer
|
||||
desc: "Dict de overrides para build_facedetailer_workflow. ckpt_name/positive/negative se detectan del workflow si faltan; resto = params del builder (denoise, steps, bbox_model, ...). {} = detect + defaults. None = sin facedetailer. keyword-only."
|
||||
output: "copia del base con las capacidades activadas encadenadas en orden (loras -> controlnet -> ipadapter -> facedetailer -> hires). Sin ninguna activada, copia del base intacta. Tras facedetailer deja un unico SaveImage (el del detailer)."
|
||||
tested: true
|
||||
tests: ["sin capacidades devuelve el base intacto (mismos nodos)", "solo loras encadena los LoraLoader", "loras + facedetailer: cadena de loras + FaceDetailer + un solo SaveImage", "ipadapter + lora: IPAdapter toma el MODEL del ultimo LoraLoader", "hires anade UltimateSDUpscale", "controlnet sin control_image propaga ValueError", "ipadapter sin ref_image propaga ValueError", "no muta el dict de entrada (pureza)", "api format valido en todas las combinaciones", "activar una capacidad cambia el conjunto de class_types"]
|
||||
test_file_path: "python/functions/ml/tests/test_comfyui_compose_capabilities.py"
|
||||
file_path: "python/functions/ml/comfyui_compose_capabilities.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
|
||||
from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow
|
||||
from ml.comfyui_compose_capabilities import comfyui_compose_capabilities
|
||||
|
||||
base = comfyui_build_txt2img_workflow("dreamshaper_8.safetensors", "a hero, 3d render style")
|
||||
|
||||
# 3 capacidades a la vez: 2 LoRAs + FaceDetailer (activar/desactivar = cambiar args)
|
||||
mixed = comfyui_compose_capabilities(
|
||||
base,
|
||||
loras=[
|
||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5},
|
||||
],
|
||||
facedetailer={"denoise": 0.45},
|
||||
# controlnet=..., ipadapter=..., hires=... -> None = desactivadas
|
||||
)
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando quieras **mezclar varias capacidades de generacion** (LoRAs + ControlNet +
|
||||
IPAdapter + FaceDetailer + hires) sobre un mismo workflow base y poder
|
||||
activar/desactivar cada una para iterar y mejorar. Es el "mixer" del grupo
|
||||
`comfyui-skill`: una sola funcion en vez de encadenar los inyectores a mano. La
|
||||
salida va directa a `comfyui_submit_workflow` (o usa el one-shot
|
||||
`comfyui_generate_mixed_oneshot` para submit + juicio).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Pura: no muta el `base_workflow` y NO valida que checkpoints/loras/modelos
|
||||
existan en el servidor. Las imagenes de control/referencia (ControlNet,
|
||||
IPAdapter) deben estar en el `input/` del servidor antes de submit.
|
||||
- **Orden fijo**: loras -> controlnet -> ipadapter -> facedetailer -> hires. El
|
||||
IPAdapter se aplica sobre el MODEL ya modificado por los LoRAs (orden correcto).
|
||||
- **hires + facedetailer NO encadenan** con las piezas actuales: ambos toman su
|
||||
imagen del VAEDecode del render base, asi que combinarlos deja a uno sin efecto
|
||||
sobre la salida final (con los dos activos, hires "gana" y facedetailer queda
|
||||
sin consumidor). Usa uno U otro por workflow. Es la limitacion documentada del
|
||||
mixer; el resto de combinaciones (loras+controlnet+ipadapter+uno de los dos
|
||||
post-procesos) encadenan limpio.
|
||||
- Cada capacidad apila coste de VRAM. En 8GB lowvram con SD1.5 entran ~2-3
|
||||
capacidades modestas (p.ej. 2 LoRAs + FaceDetailer a 512px). Apilar IPAdapter
|
||||
FaceID + ControlNet + hires + facedetailer a la vez puede dar OOM: baja
|
||||
resolucion o desactiva capacidades.
|
||||
- Errores de incompatibilidad (controlnet sin `control_image`, ipadapter sin
|
||||
`ref_image`, mode invalido) se propagan como `ValueError` del inyector, no
|
||||
petan en silencio.
|
||||
Reference in New Issue
Block a user