feat(gamedev): comfyui_build_asset_variant_workflow — variantes img2img de un asset existente
Primer builder gamedev-2d de transformacion (img2img) en vez de generacion (txt2img): parte de un asset ya generado y produce una variante coherente (ice/fire/damaged/golden tier) cambiando material/paleta/estado y conservando silueta, pose y composicion via denoise medio (~0.5). Compone comfyui_build_img2img_workflow + comfyui_inject_lora + ImageScale opcional. Probado e2e en GPU SD1.5: variante ice del goblin del demo pack (prompt_id 5e4a5d3d) — silueta conservada (luminance corr 0.63) + paleta a frio (blueness B-R -1.6 -> +1.9). Subseccion nueva en docs/capabilities y report 0181.
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
---
|
||||
name: comfyui_build_asset_variant_workflow
|
||||
kind: function
|
||||
lang: py
|
||||
domain: ml
|
||||
purity: pure
|
||||
version: 1.0.0
|
||||
signature: "def comfyui_build_asset_variant_workflow(input_image: str, variant: str, *, checkpoint: str = \"dreamshaper_8.safetensors\", denoise: float = 0.5, style: str = \"game asset\", size: int | None = 512, seed: int = 0, lora: str | None = None, lora_strength: float = 1.0, upscale_method: str = \"lanczos\", crop: str = \"disabled\", negative: str | None = None, steps: int = 28, cfg: float = 7.0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", filename_prefix: str = \"asset_variant\") -> dict"
|
||||
description: "Construye el dict (API format) del workflow de una VARIANTE img2img de un asset 2D ya generado: parte de una IMAGEN existente (un sprite de enemigo, un icono...) y produce una version coherente que cambia material/paleta/tier/estado (ice element, fire element, battle-damaged, golden tier 2, corrupted) manteniendo la composicion, la pose y la silueta del original. A diferencia de los builders gamedev hermanos (enemy_creature, item_icon...), que parten de TEXTO (txt2img desde ruido), este parte de una imagen via img2img con denoise MEDIO (~0.45-0.6): el KSampler arranca del latente de la imagen base, no de ruido. Normaliza el tamano con un ImageScale opcional (size) o preserva las dimensiones del original (size=None). Compone comfyui_build_img2img_workflow + comfyui_inject_lora (estilo opcional). Pura, sin red ni I/O. class_types verificados contra /object_info (8GB lowvram)."
|
||||
tags: [comfyui, ml, gamedev-2d, img2img, variant, asset-transform, stable-diffusion, workflow]
|
||||
uses_functions: [comfyui_build_img2img_workflow_py_ml, comfyui_inject_lora_py_ml]
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
params:
|
||||
- name: input_image
|
||||
desc: "Nombre del archivo de la imagen base dentro de la carpeta input/ del servidor ComfyUI (un asset YA generado). Lo carga el nodo LoadImage. Subelo antes con POST /upload/image o copialo a ~/ComfyUI/input/. No puede estar vacio."
|
||||
- name: variant
|
||||
desc: "Descripcion de la variante a producir (ej. 'ice element, frozen', 'fire element, molten', 'battle-damaged, cracked', 'golden tier 2', 'corrupted shadow'). Reescribe material/paleta/estado del asset manteniendo su composicion. No describe el sujeto desde cero: transforma el que ya existe en input_image. No puede estar vacio."
|
||||
- name: checkpoint
|
||||
desc: "Checkpoint del servidor. 'dreamshaper_8.safetensors' (SD1.5, holgado en 8GB lowvram) por defecto. keyword-only."
|
||||
- name: denoise
|
||||
desc: "Fuerza de denoising del KSampler (cuanto se aparta del original). ~0.3 apenas cambia; 0.45-0.6 (recomendado) cambia material/paleta conservando silueta/pose; ~0.8 se aleja y empieza a ser casi txt2img. Se clampa a [0.0, 1.0]. keyword-only."
|
||||
- name: style
|
||||
desc: "Descriptor de estilo que mantiene coherentes las variantes de un set (ej. 'game asset', 'dark fantasy creature', 'pixel art'). Mismo style + checkpoint + (lora) en todas las variantes del mismo asset. keyword-only."
|
||||
- name: size
|
||||
desc: "Lado en px al que se NORMALIZA la imagen base antes de encodearla (inserta un ImageScale a size x size). None = no escala; la variante hereda las dimensiones EXACTAS del original (preserva proporcion sin deformar). 512 por defecto (SD1.5). keyword-only."
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'dark_fantasy_sd15.safetensors'). None = sin LoRA. keyword-only."
|
||||
- name: lora_strength
|
||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||
- name: upscale_method
|
||||
desc: "Metodo del ImageScale ('lanczos', 'bilinear', 'bicubic', 'area', 'nearest-exact'). Solo se usa si size no es None. keyword-only."
|
||||
- name: crop
|
||||
desc: "Modo de recorte del ImageScale ('disabled' conserva todo el contenido, 'center' recorta al centro para encajar el ratio). Solo si size no es None. keyword-only."
|
||||
- name: negative
|
||||
desc: "Prompt negativo. None usa el negativo por defecto pensado para variantes (conservar pose/composicion, una figura, fondo limpio). keyword-only."
|
||||
- name: steps
|
||||
desc: "Pasos de sampling del KSampler. keyword-only."
|
||||
- name: cfg
|
||||
desc: "Classifier-free guidance scale. keyword-only."
|
||||
- name: sampler_name
|
||||
desc: "Nombre del sampler (ej. 'dpmpp_2m', 'euler'). keyword-only."
|
||||
- name: scheduler
|
||||
desc: "Scheduler del sampler (ej. 'karras', 'normal'). keyword-only."
|
||||
- name: filename_prefix
|
||||
desc: "Prefijo del archivo de salida en SaveImage. keyword-only."
|
||||
output: "dict en API format listo para comfyui_submit_workflow: img2img base (parte de input_image) con prompt de variante + ImageScale opcional (normaliza a size) + LoRA opcional. Nodos: CheckpointLoaderSimple '4', LoadImage '10', VAEEncode '11', CLIPTextEncode '6'/'7', KSampler '3' (denoise medio), VAEDecode '8', SaveImage '9', + ImageScale y LoraLoader si aplican."
|
||||
tested: false
|
||||
file_path: python/functions/ml/comfyui_build_asset_variant_workflow.py
|
||||
---
|
||||
|
||||
Construye el dict (API format) del workflow de una **variante de un asset 2D que ya
|
||||
existe** (img2img). Builder gamedev hermano de `comfyui_build_enemy_creature_workflow`
|
||||
e `comfyui_build_item_icon_workflow`, pero con un eje distinto: en vez de generar un
|
||||
TIPO de asset desde texto, **transforma** una imagen concreta (un sprite ya generado)
|
||||
en una variante coherente — la version "de hielo", "de fuego", "dañada" o "tier 2
|
||||
dorada" — conservando silueta, pose y composición del original.
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
|
||||
from ml.comfyui_build_asset_variant_workflow import comfyui_build_asset_variant_workflow
|
||||
|
||||
# Variante "de hielo" de un sprite de goblin ya generado (subido al input/ del server)
|
||||
wf = comfyui_build_asset_variant_workflow(
|
||||
"enemy_creature_00001_.png", # asset existente en el input/ de ComfyUI
|
||||
"ice element, frozen", # la variante a producir
|
||||
style="dark fantasy creature, game asset",
|
||||
denoise=0.5, # medio: cambia material/paleta, conserva silueta
|
||||
seed=7,
|
||||
)
|
||||
# wf parte de una imagen (img2img), NO de ruido:
|
||||
# "VAEEncode" in {n["class_type"] for n in wf.values()} # True
|
||||
# "EmptyLatentImage" not in {n["class_type"] for n in wf.values()} # True (no es txt2img)
|
||||
# wf["10"]["inputs"]["image"] == "enemy_creature_00001_.png"
|
||||
# wf["3"]["inputs"]["denoise"] == 0.5
|
||||
# "ice element, frozen" in wf["6"]["inputs"]["text"]
|
||||
```
|
||||
|
||||
El bloque 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 `comfyui_build_img2img_workflow`.
|
||||
Usa el import de arriba o un heredoc.
|
||||
|
||||
Set de variantes del MISMO asset (mismo `input_image`/`style`/`seed`, distinto `variant`):
|
||||
|
||||
```python
|
||||
for v in ["ice element, frozen", "fire element, molten", "battle-damaged, cracked", "golden tier 2"]:
|
||||
wf = comfyui_build_asset_variant_workflow("enemy_creature_00001_.png", v,
|
||||
style="dark fantasy creature, game asset",
|
||||
denoise=0.5, seed=7)
|
||||
# enviar con comfyui_submit_workflow -> familia coherente de variantes
|
||||
```
|
||||
|
||||
Para enviar a la GPU: subir la base con `POST /upload/image`, luego
|
||||
`comfyui_submit_workflow(wf)` + `comfyui_wait_result(prompt_id)` +
|
||||
`comfyui_fetch_output_image(filename)`.
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando ya tienes un asset 2D generado y quieres **derivar variantes coherentes** de
|
||||
él (elemento/material/tier/estado) sin redibujar desde cero: el sprite de hielo del
|
||||
mismo enemigo, la armadura dorada del mismo personaje, la versión dañada del mismo
|
||||
prop. Es img2img con denoise medio que conserva la composición original. Para generar
|
||||
un asset NUEVO desde texto usa los builders txt2img hermanos
|
||||
(`comfyui_build_enemy_creature_workflow`, `comfyui_build_item_icon_workflow`...); para
|
||||
ampliar/refinar resolución usa `comfyui_build_upscale_workflow`; para img2img genérico
|
||||
sin scaffolding de variante usa `comfyui_build_img2img_workflow` directo.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Es **img2img**, no txt2img: SIEMPRE parte de una imagen (`input_image`), no de ruido
|
||||
en blanco. Esa imagen debe existir en la carpeta `input/` del servidor ComfyUI
|
||||
(subir con `POST /upload/image` o copiar a `~/ComfyUI/input/`). Es pura: NO valida
|
||||
que exista; si no está, ComfyUI rechaza el workflow con HTTP 400 al enviarlo. Valida
|
||||
antes con `comfyui_validate_workflow`.
|
||||
- `denoise` es la palanca clave: cerca de 0.0 apenas cambia (variante invisible);
|
||||
0.45-0.6 es el rango útil (cambia material/paleta manteniendo silueta); cerca de 0.8
|
||||
se aleja del original y deriva la pose/composición (deja de ser variante coherente y
|
||||
se acerca a un txt2img). Default 0.5.
|
||||
- `size` reescala la imagen base a `size x size` con un ImageScale ANTES de encodear.
|
||||
Con `size=512` y un asset cuadrado 512 es no-op de tamaño; con un asset NO cuadrado y
|
||||
`crop="disabled"` el ImageScale fuerza el ratio cuadrado y puede deformar — pasa
|
||||
`size=None` para preservar las dimensiones/proporción exactas del original, o
|
||||
`crop="center"` para recortar al centro en vez de deformar.
|
||||
- El prompt refuerza "same composition, same pose, same silhouette" además del denoise
|
||||
medio; aun así, denoise alto o un `variant` que implique cambio de forma (ej. "giant
|
||||
version") puede alterar la silueta. Para variantes solo de paleta/material, mantén
|
||||
denoise ≤0.55.
|
||||
- Asume checkpoint con VAE embebido (VAEEncode/VAEDecode usan el VAE del checkpoint).
|
||||
Para un VAE externo hay que reconectar esas entradas a mano.
|
||||
- 8GB lowvram: SD1.5 a 512² va holgado. Si OOM, baja `size` (384) o `denoise`; NO subas
|
||||
a SDXL en 8GB para esto.
|
||||
@@ -0,0 +1,262 @@
|
||||
"""Construye el workflow ComfyUI de una VARIANTE de un asset ya generado (img2img).
|
||||
|
||||
A diferencia de los builders gamedev hermanos (enemy_creature, item_icon,
|
||||
ui_hud...), que parten de TEXTO (txt2img desde ruido), este builder parte de una
|
||||
IMAGEN que ya existe y produce una variante COHERENTE: cambia paleta, material,
|
||||
tier o estado del asset manteniendo la composicion, la pose y la silueta del
|
||||
original. Es el caso real de gamedev: tienes el sprite de un enemigo y quieres su
|
||||
version "de hielo", "de fuego", "danada en combate" o "tier 2 dorada" sin redibujar
|
||||
desde cero.
|
||||
|
||||
El mecanismo es img2img con denoise MEDIO: el KSampler parte del latente de la
|
||||
imagen base (LoadImage -> [ImageScale opcional] -> VAEEncode), no de ruido, asi que
|
||||
con denoise ~0.45-0.6 conserva la estructura global (silueta/pose) mientras el
|
||||
prompt de la variante reescribe material y color. Denoise bajo (~0.3) apenas cambia;
|
||||
alto (~0.8) se aleja del original y empieza a ser casi txt2img.
|
||||
|
||||
Cableado:
|
||||
|
||||
CheckpointLoaderSimple -> [LoraLoader opcional de estilo] -> KSampler
|
||||
LoadImage -> [ImageScale opcional a size x size] -> VAEEncode -> KSampler.latent
|
||||
CLIPTextEncode (prompt de variante + "same composition/pose/silhouette")
|
||||
KSampler (denoise medio) -> VAEDecode -> SaveImage
|
||||
|
||||
Compone:
|
||||
- comfyui_build_img2img_workflow -> base img2img (LoadImage/VAEEncode/KSampler con denoise)
|
||||
- comfyui_inject_lora -> LoRA de estilo opcional (consistencia con el set)
|
||||
|
||||
Por que ImageScale opcional y no EmptyLatentImage: en img2img el tamano de salida lo
|
||||
fija la imagen base (no hay EmptyLatentImage). Para poder NORMALIZAR todos los assets
|
||||
del set a una resolucion comun (`size`), se inserta un ImageScale entre LoadImage y
|
||||
VAEEncode que reescala la base antes de encodear. Si size=None, no se escala y la
|
||||
variante hereda las dimensiones exactas del original (preserva proporcion sin
|
||||
deformar). Es la diferencia clave con un txt2img: aqui SIEMPRE hay una imagen de
|
||||
entrada de la que se parte; el prompt no genera en blanco, transforma.
|
||||
|
||||
Por que el prompt empuja "same composition, same pose, same silhouette": el denoise
|
||||
medio ya conserva la estructura, pero reforzarlo en el texto reduce la deriva de
|
||||
pose/encuadre y mantiene la variante alineada con el original (lo que se quiere para
|
||||
un set coherente: misma figura, distinto material/tier).
|
||||
|
||||
class_types/inputs verificados contra /object_info del servidor (8GB lowvram):
|
||||
CheckpointLoaderSimple, LoadImage, ImageScale, VAEEncode, CLIPTextEncode, KSampler,
|
||||
VAEDecode, SaveImage, LoraLoader.
|
||||
|
||||
Funcion pura: sin red, sin I/O. No muta dicts de entrada (copia profunda al insertar
|
||||
ImageScale). NO valida que input_image/checkpoint/lora existan en el servidor (eso
|
||||
es responsabilidad de comfyui_validate_workflow antes de enviar). Determinista para
|
||||
los mismos argumentos.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
# Negativo por defecto pensado para variantes de asset: conservar UNA figura entera,
|
||||
# bien formada, fondo limpio, SIN cambiar la composicion/pose y sin texto/marcas ni
|
||||
# objetos extra. No filtra material ni paleta (ice/fire/golden/damaged son validos).
|
||||
_VARIANT_NEGATIVE = (
|
||||
"blurry, lowres, deformed, disfigured, bad anatomy, extra limbs, "
|
||||
"different pose, different composition, different framing, extra objects, "
|
||||
"duplicate, multiple subjects, text, watermark, signature, logo, "
|
||||
"cropped, cut off, out of frame, jpeg artifacts"
|
||||
)
|
||||
|
||||
|
||||
def _inject_image_scale(
|
||||
workflow: dict, *, size: int, upscale_method: str, crop: str
|
||||
) -> dict:
|
||||
"""Inserta un nodo ImageScale entre LoadImage y VAEEncode para normalizar el tamano.
|
||||
|
||||
Reescala la imagen base a size x size ANTES de encodearla al latente, de modo que
|
||||
la variante salga a la resolucion deseada en lugar de heredar la del original.
|
||||
Repunta VAEEncode.pixels a la salida del ImageScale. Pura: trabaja sobre copia.
|
||||
"""
|
||||
wf = copy.deepcopy(workflow)
|
||||
load_id = next(
|
||||
(nid for nid, n in wf.items() if n.get("class_type") == "LoadImage"), None
|
||||
)
|
||||
vaeencode_id = next(
|
||||
(nid for nid, n in wf.items() if n.get("class_type") == "VAEEncode"), None
|
||||
)
|
||||
if load_id is None or vaeencode_id is None:
|
||||
raise ValueError(
|
||||
"comfyui_build_asset_variant_workflow: no se encontro LoadImage/VAEEncode "
|
||||
"para insertar ImageScale"
|
||||
)
|
||||
numeric = [int(k) for k in wf.keys() if str(k).isdigit()]
|
||||
scale_id = str((max(numeric) + 1) if numeric else len(wf) + 1)
|
||||
# La fuente de pixeles que hoy alimenta el VAEEncode (normalmente LoadImage[0]).
|
||||
src = wf[vaeencode_id]["inputs"].get("pixels", [load_id, 0])
|
||||
wf[scale_id] = {
|
||||
"class_type": "ImageScale",
|
||||
"inputs": {
|
||||
"image": list(src),
|
||||
"upscale_method": upscale_method,
|
||||
"width": int(size),
|
||||
"height": int(size),
|
||||
"crop": crop,
|
||||
},
|
||||
}
|
||||
wf[vaeencode_id]["inputs"]["pixels"] = [scale_id, 0]
|
||||
return wf
|
||||
|
||||
|
||||
def comfyui_build_asset_variant_workflow(
|
||||
input_image: str,
|
||||
variant: str,
|
||||
*,
|
||||
checkpoint: str = "dreamshaper_8.safetensors",
|
||||
denoise: float = 0.5,
|
||||
style: str = "game asset",
|
||||
size: int | None = 512,
|
||||
seed: int = 0,
|
||||
lora: str | None = None,
|
||||
lora_strength: float = 1.0,
|
||||
upscale_method: str = "lanczos",
|
||||
crop: str = "disabled",
|
||||
negative: str | None = None,
|
||||
steps: int = 28,
|
||||
cfg: float = 7.0,
|
||||
sampler_name: str = "dpmpp_2m",
|
||||
scheduler: str = "karras",
|
||||
filename_prefix: str = "asset_variant",
|
||||
) -> dict:
|
||||
"""Construye el dict (API format) de una variante img2img de un asset existente.
|
||||
|
||||
Args:
|
||||
input_image: nombre del archivo de la imagen base dentro de la carpeta
|
||||
input/ del servidor ComfyUI (un asset YA generado: un sprite de enemigo,
|
||||
un icono de objeto...). Lo carga el nodo LoadImage. Subelo antes con
|
||||
POST /upload/image o copialo a ~/ComfyUI/input/. No puede estar vacio.
|
||||
variant: descripcion de la variante a producir (ej. "ice element, frozen",
|
||||
"fire element, molten", "battle-damaged, cracked", "golden tier 2",
|
||||
"corrupted shadow"). Es lo que reescribe material/paleta/estado del asset
|
||||
manteniendo su composicion. No puede estar vacio. Es lo que diferencia
|
||||
este builder de un txt2img: NO describe el sujeto desde cero, transforma
|
||||
uno que ya existe en la imagen base.
|
||||
checkpoint: checkpoint del servidor. 'dreamshaper_8.safetensors' (SD1.5,
|
||||
holgado en 8GB lowvram) por defecto. keyword-only.
|
||||
denoise: fuerza de denoising del KSampler (cuanto se aparta del original).
|
||||
~0.3 apenas cambia; 0.45-0.6 (recomendado) cambia material/paleta
|
||||
conservando silueta/pose; ~0.8 se aleja y empieza a ser casi txt2img. Se
|
||||
clampa a [0.0, 1.0]. keyword-only.
|
||||
style: descriptor de estilo que mantiene coherentes las variantes de un set
|
||||
(ej. "game asset", "dark fantasy creature", "pixel art"). Pasa el MISMO
|
||||
style + checkpoint + (lora) a todas las variantes del mismo asset.
|
||||
keyword-only.
|
||||
size: lado en px al que se NORMALIZA la imagen base antes de encodearla
|
||||
(inserta un ImageScale a size x size). None = no escala, la variante
|
||||
hereda las dimensiones EXACTAS del original (preserva proporcion sin
|
||||
deformar). 512 por defecto (SD1.5). keyword-only.
|
||||
seed: semilla del KSampler. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'dark_fantasy_sd15.safetensors'). None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
upscale_method: metodo del ImageScale ('lanczos', 'bilinear', 'bicubic',
|
||||
'area', 'nearest-exact'). Solo se usa si size no es None. keyword-only.
|
||||
crop: modo de recorte del ImageScale ('disabled' conserva todo el contenido,
|
||||
'center' recorta al centro para encajar el ratio). Solo si size no es
|
||||
None. keyword-only.
|
||||
negative: prompt negativo. None usa el negativo por defecto pensado para
|
||||
variantes (conservar pose/composicion, una figura, fondo limpio).
|
||||
keyword-only.
|
||||
steps, cfg, sampler_name, scheduler, filename_prefix: parametros de
|
||||
generacion. keyword-only.
|
||||
|
||||
Returns:
|
||||
dict en API format listo para comfyui_submit_workflow: img2img base (parte de
|
||||
input_image) con prompt de variante ('{variant}, {style}, same composition,
|
||||
same pose, same silhouette, ...') + ImageScale opcional (normaliza a size) +
|
||||
LoRA de estilo opcional. Es UNA variante; un set de variantes del MISMO asset
|
||||
-> llamar por `variant` con el mismo input_image/style/checkpoint/seed.
|
||||
|
||||
Raises:
|
||||
ValueError: si input_image o variant estan vacios, o si la base no tiene
|
||||
LoadImage/VAEEncode donde insertar el ImageScale (propagado por el helper).
|
||||
"""
|
||||
from ml.comfyui_build_img2img_workflow import comfyui_build_img2img_workflow
|
||||
|
||||
if not input_image or not input_image.strip():
|
||||
raise ValueError(
|
||||
"comfyui_build_asset_variant_workflow: 'input_image' no puede estar vacio"
|
||||
)
|
||||
if not variant or not variant.strip():
|
||||
raise ValueError(
|
||||
"comfyui_build_asset_variant_workflow: 'variant' no puede estar vacio"
|
||||
)
|
||||
|
||||
input_image = input_image.strip()
|
||||
variant = variant.strip()
|
||||
denoise = max(0.0, min(1.0, float(denoise)))
|
||||
lora_strength = max(0.0, min(2.0, float(lora_strength)))
|
||||
neg = _VARIANT_NEGATIVE if negative is None else negative
|
||||
|
||||
# Prompt de variante: reescribe material/paleta/estado pero refuerza que la
|
||||
# composicion, pose y silueta del original se conservan (img2img coherente).
|
||||
positive = (
|
||||
f"{variant}, {style}, same composition, same pose, same silhouette, "
|
||||
"consistent design, high detail"
|
||||
)
|
||||
|
||||
wf = comfyui_build_img2img_workflow(
|
||||
checkpoint,
|
||||
input_image,
|
||||
positive,
|
||||
neg,
|
||||
denoise=denoise,
|
||||
steps=steps,
|
||||
cfg=cfg,
|
||||
seed=seed,
|
||||
sampler_name=sampler_name,
|
||||
scheduler=scheduler,
|
||||
)
|
||||
|
||||
# El builder base hardcodea filename_prefix="comfy_img2img"; lo repuntamos.
|
||||
save_id = next(
|
||||
(nid for nid, n in wf.items() if n.get("class_type") == "SaveImage"), None
|
||||
)
|
||||
if save_id is not None:
|
||||
wf[save_id]["inputs"]["filename_prefix"] = filename_prefix
|
||||
|
||||
if size is not None:
|
||||
wf = _inject_image_scale(
|
||||
wf, size=size, upscale_method=upscale_method, crop=crop
|
||||
)
|
||||
|
||||
if lora:
|
||||
from ml.comfyui_inject_lora import comfyui_inject_lora
|
||||
|
||||
wf = comfyui_inject_lora(
|
||||
wf, lora, strength_model=lora_strength, strength_clip=lora_strength
|
||||
)
|
||||
|
||||
return wf
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import json
|
||||
|
||||
wf = comfyui_build_asset_variant_workflow(
|
||||
"enemy_creature_00001_.png",
|
||||
"ice element, frozen",
|
||||
style="dark fantasy creature, game asset",
|
||||
denoise=0.5,
|
||||
seed=7,
|
||||
)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"nodes": list(wf),
|
||||
"classes": sorted({n["class_type"] for n in wf.values()}),
|
||||
"denoise": wf["3"]["inputs"]["denoise"],
|
||||
"positive": wf["6"]["inputs"]["text"],
|
||||
"input_image": wf["10"]["inputs"]["image"],
|
||||
},
|
||||
indent=2,
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user