feat(gamedev): comfyui_build_dialogue_box_workflow — caja de diálogo/bocadillo/panel de texto
Builder del contenedor de diálogo de juego (RPG, visual novel, aventura): marco apaisado (768x256) con borde decorativo e interior plano reservado para el texto del motor. Distinto de ui_hud (elementos sueltos): es el panel-contenedor completo. Compone txt2img + inject_lora + Image Rembg (alpha). Pura, dict API format. 7 tests offline verdes; 1 generación real en GPU (medieval wood+gold, 768x256 RGBA). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
---
|
||||
name: comfyui_build_dialogue_box_workflow
|
||||
kind: function
|
||||
lang: py
|
||||
domain: ml
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "def comfyui_build_dialogue_box_workflow(box_style: str = \"fantasy RPG dialogue box\", *, shape: str = \"rounded panel\", checkpoint: str = \"dreamshaper_8.safetensors\", width: int = 768, height: int = 256, transparent: bool = True, seed: int = 0, lora: str | None = None, lora_strength: float = 1.0, rembg_model: str = \"u2net\", negative: str | None = None, steps: int = 28, cfg: float = 7.0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", filename_prefix: str = \"dialogue_box\") -> dict"
|
||||
description: "Construye el dict (API format) del workflow de UNA caja de dialogo / bocadillo / panel de texto de juego (RPG, visual novel, aventura): el contenedor de UI apaisado con borde decorativo y un interior plano y vacio reservado para que el motor de juego renderice el texto de la conversacion encima. DISTINTO de comfyui_build_ui_hud_workflow (elementos sueltos: botones/barras/iconos): esto es el contenedor de dialogo completo. Compone comfyui_build_txt2img_workflow + comfyui_inject_lora (estilo opcional) + Image Rembg (fondo transparente si transparent). Hermano de comfyui_build_ui_hud/card_art_workflow. Pura, sin red ni I/O. class_types verificados contra /object_info."
|
||||
tags: [comfyui, ml, gamedev, gamedev-2d, ui, dialogue, dialogue-box, text-box, panel, workflow]
|
||||
uses_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_inject_lora_py_ml]
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: []
|
||||
params:
|
||||
- name: box_style
|
||||
desc: "Descriptor del estilo del contenedor de dialogo (ej. 'fantasy RPG dialogue box', 'medieval fantasy dialogue box, wood and gold', 'sci-fi terminal text box, neon glow', 'visual novel text panel, soft pastel'). Se inserta en un prompt scaffold de caja de dialogo. No puede estar vacio."
|
||||
- name: shape
|
||||
desc: "Forma del panel (ej. 'rounded panel', 'rectangular banner', 'scroll parchment', 'stone tablet', 'speech bubble'). Mantiene coherentes las cajas de un juego. keyword-only."
|
||||
- name: checkpoint
|
||||
desc: "Checkpoint del servidor. 'dreamshaper_8.safetensors' (SD1.5, holgado en 8GB lowvram) por defecto; 'juggernaut_xl_v11.safetensors' para SDXL (mas VRAM, subir width/height). keyword-only."
|
||||
- name: width
|
||||
desc: "Ancho del panel en px. Apaisado de caja de dialogo -> width > height. 768 por defecto. keyword-only."
|
||||
- name: height
|
||||
desc: "Alto del panel en px. 256 por defecto (panel bajo y ancho). keyword-only."
|
||||
- name: transparent
|
||||
desc: "Si True inyecta Image Rembg y el PNG sale con alpha (fondo recortado alrededor del borde). False = panel opaco sobre fondo plano, recortable luego por el caller. keyword-only."
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'detail_tweaker_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: rembg_model
|
||||
desc: "Modelo Rembg ('u2net' general, 'isnet-anime' para anime). Solo se usa si transparent=True. keyword-only."
|
||||
- name: negative
|
||||
desc: "Prompt negativo. None usa el negativo por defecto pensado para la caja de dialogo (panel limpio, interior plano y vacio, sin texto ni personajes/escena). keyword-only."
|
||||
- name: steps
|
||||
desc: "Pasos del KSampler. keyword-only."
|
||||
- name: cfg
|
||||
desc: "CFG del KSampler. keyword-only."
|
||||
- name: sampler_name
|
||||
desc: "Sampler del KSampler. keyword-only."
|
||||
- name: scheduler
|
||||
desc: "Scheduler del KSampler. keyword-only."
|
||||
- name: filename_prefix
|
||||
desc: "Prefijo del PNG en output/. keyword-only."
|
||||
output: "dict en API format listo para comfyui_submit_workflow: base txt2img apaisada con prompt scaffold de caja de dialogo ('{box_style}, {shape}, game UI dialogue box frame, ornate border, empty flat interior for text, plain background') + LoRA de estilo opcional + Image Rembg (si transparent). UNA caja; set coherente -> llamar con mismo box_style/shape/checkpoint/lora. El texto de la conversacion lo pone el motor sobre el interior plano, no este workflow."
|
||||
tested: true
|
||||
tests: ["golden transparent: clases CheckpointLoaderSimple/KSampler/VAEDecode/SaveImage/Image Rembg; box_style + 'game UI dialogue box frame' + 'ornate border' + 'empty flat interior for text' + 'plain background' en prompt; SaveImage <- Rembg; transparency True", "edge transparent=False: sin Rembg, SaveImage <- VAEDecode", "edge dims apaisadas: width==896 > height==224", "edge shape en prompt", "edge lora: LoraLoader presente con strength", "error box_style vacio -> ValueError", "determinismo"]
|
||||
test_file_path: "python/functions/ml/comfyui_build_dialogue_box_workflow_test.py"
|
||||
file_path: "python/functions/ml/comfyui_build_dialogue_box_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_dialogue_box_workflow import comfyui_build_dialogue_box_workflow
|
||||
|
||||
# Una caja de dialogo medieval de madera y oro, apaisada, con fondo transparente (alpha).
|
||||
wf = comfyui_build_dialogue_box_workflow(
|
||||
"medieval fantasy dialogue box, wood and gold",
|
||||
shape="rounded panel",
|
||||
transparent=True,
|
||||
seed=42,
|
||||
)
|
||||
# Set de cajas coherentes: misma firma de estilo, varia solo el matiz.
|
||||
# for st in ["fantasy dialogue box", "sci-fi terminal text box, neon glow",
|
||||
# "visual novel text panel, soft pastel"]:
|
||||
# wf = comfyui_build_dialogue_box_workflow(st, shape="rounded panel",
|
||||
# lora="detail_tweaker_sd15.safetensors", seed=42)
|
||||
# comfyui_submit_workflow(wf) # -> comfyui_wait_result -> comfyui_fetch_output_image
|
||||
# El motor de juego renderiza el texto de la conversacion sobre el interior plano.
|
||||
```
|
||||
|
||||
O lanzable directo con: `./fn run comfyui_build_dialogue_box_workflow` (imprime nodos + class_types del ejemplo).
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando necesites el MARCO de la caja de texto donde aparece el dialogo de una
|
||||
conversacion (RPG, visual novel, aventura grafica): un panel apaisado con borde
|
||||
decorativo y un interior plano reservado para el texto del motor. Usa esto, NO
|
||||
`comfyui_build_ui_hud_workflow`, cuando lo que quieres es el CONTENEDOR de dialogo
|
||||
completo (con su borde y su area de texto), no un elemento suelto del HUD (boton,
|
||||
barra, icono). Pasa el MISMO `box_style` + `shape` + `checkpoint` + (`lora`) a todas
|
||||
las cajas de un juego para que combinen. `transparent` recorta el fondo (alpha) listo
|
||||
para superponer en pantalla.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **El interior debe quedar PLANO/LISO**: el negativo por defecto rechaza
|
||||
"busy interior / cluttered / decorated interior / illustration inside" y el scaffold
|
||||
empuja a "empty flat interior for text" para que el motor escriba el texto encima sin
|
||||
competir con detalle horneado. Si el modelo decora el interior, refuerza `box_style`
|
||||
con "simple flat inner area" o pasa un `negative` propio mas estricto.
|
||||
- **El texto del dialogo lo pone el motor, NO la imagen**: el negativo empuja a
|
||||
"no text / no letters / no words" para que la caja salga vacia; la conversacion se
|
||||
renderiza en el juego sobre el panel. Si quieres texto horneado (raro), pasa un
|
||||
`negative` sin "text, letters, words".
|
||||
- **Diferencia con ui_hud**: ui_hud = elementos sueltos (botones, barras, iconos,
|
||||
cursores); este builder = el panel-contenedor de dialogo apaisado. No los confundas:
|
||||
si quieres un boton o una barra de vida, usa `comfyui_build_ui_hud_workflow`.
|
||||
- **El recorte usa Rembg, NO luma-to-alpha**: una caja de dialogo es una pieza solida
|
||||
con silueta definida (panel + borde), rembg la recorta limpio.
|
||||
`comfyui_matting_luma_to_alpha` es para translucidos sobre negro (humo/fuego/magia)
|
||||
y aplanaria el panel — no la uses aqui.
|
||||
- **Apaisado por defecto**: `width=768 > height=256` da la proporcion de panel de
|
||||
conversacion al pie de la pantalla. Un bocadillo cuadrado -> sube `height`; un banner
|
||||
muy ancho -> sube `width`.
|
||||
- **Coherencia del set = mismos parametros**: si cambias `box_style`/`shape`/
|
||||
`checkpoint`/`lora`/`seed` entre cajas, dejan de combinar. Fija esos y varia solo el
|
||||
matiz del `box_style`.
|
||||
- **SDXL pide mas VRAM y resolucion**: con `checkpoint="juggernaut_xl_v11.safetensors"`
|
||||
sube `width`/`height`; con dreamshaper_8 (SD1.5) deja 768x256 (holgado en 8GB lowvram).
|
||||
- `transparent=False` deja el panel opaco sobre fondo plano: util si prefieres recortar
|
||||
fuera del workflow o el motor compone sobre un slot solido.
|
||||
- Es una funcion **pura**: solo arma el dict. La generacion real (GPU) la hacen
|
||||
`comfyui_submit_workflow` + `comfyui_wait_result` + `comfyui_fetch_output_image`.
|
||||
@@ -0,0 +1,229 @@
|
||||
"""Construye el workflow ComfyUI de UNA caja de dialogo / bocadillo / panel de texto en API format.
|
||||
|
||||
Caja de dialogo de juego (RPG, visual novel, aventura): el contenedor de UI donde
|
||||
aparece el texto de conversacion. Marco apaisado con borde decorativo y un interior
|
||||
plano y liso reservado para que el motor de juego renderice el texto encima. Es el
|
||||
builder hermano de comfyui_build_ui_hud_workflow / comfyui_build_card_art_workflow:
|
||||
mismo patron (PURO, dict API format) que compone funciones existentes del registry,
|
||||
no reescribe el grafo.
|
||||
|
||||
IMPORTANTE — diferencia con comfyui_build_ui_hud_workflow: ui_hud genera ELEMENTOS
|
||||
SUELTOS de interfaz (un boton, una barra de vida, un icono, un cursor). Este builder
|
||||
genera el CONTENEDOR DE DIALOGO completo: un panel apaisado con borde ornamental y
|
||||
un area interior intencionalmente plana/vacia donde el motor escribe el texto de la
|
||||
conversacion. No es un elemento del HUD, es el marco de la caja de texto.
|
||||
|
||||
Cableado:
|
||||
|
||||
CheckpointLoaderSimple -> [LoraLoader opcional de estilo] -> KSampler
|
||||
-> CLIPTextEncode (prompt scaffold de caja de dialogo) ...
|
||||
-> VAEDecode -> [Image Rembg opcional] -> SaveImage
|
||||
|
||||
Compone:
|
||||
- comfyui_build_txt2img_workflow -> base txt2img apaisada (width > height)
|
||||
- comfyui_inject_lora -> LoRA de estilo opcional (consistencia de UI)
|
||||
- 'Image Rembg (Remove Background)' (helper local) -> fondo transparente (alpha)
|
||||
|
||||
Por que Rembg y NO comfyui_matting_luma_to_alpha: una caja de dialogo es una pieza
|
||||
SOLIDA con silueta definida (un panel con su borde); rembg recorta limpio el marco
|
||||
dejando alpha alrededor. La luma-to-alpha es para translucidos sobre negro
|
||||
(humo/fuego/magia) y aplanaria el panel. Si el caller prefiere recortar fuera del
|
||||
workflow (transparent=False) deja la imagen opaca sobre fondo plano, recortable
|
||||
luego por el pipeline o el caller.
|
||||
|
||||
Por que apaisado (width > height): una caja de dialogo ocupa el ancho de la pantalla
|
||||
y es baja de alto (una/dos lineas de texto). 768x256 (SD1.5) da la proporcion tipica
|
||||
de panel de conversacion al pie de la pantalla. El interior se mantiene plano para no
|
||||
competir con el texto del motor.
|
||||
|
||||
class_types/inputs verificados contra /object_info del servidor (8GB lowvram) a
|
||||
traves de los builders que compone: CheckpointLoaderSimple, CLIPTextEncode,
|
||||
EmptyLatentImage, KSampler, VAEDecode, SaveImage, LoraLoader,
|
||||
'Image Rembg (Remove Background)' (transparency BOOLEAN).
|
||||
|
||||
Funcion pura: sin red, sin I/O. No muta dicts de entrada (copia profunda en el
|
||||
helper de rembg). 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 una caja de dialogo: un panel apaisado limpio,
|
||||
# con el INTERIOR PLANO y VACIO (sin texto, sin imagenes dentro) para que el motor
|
||||
# escriba el texto encima, sin personajes ni escena que ensucien el contenedor.
|
||||
_DIALOGUE_NEGATIVE = (
|
||||
"blurry, lowres, character, person, face, landscape, scene, "
|
||||
"text, letters, words, label, watermark, signature, "
|
||||
"busy interior, cluttered, decorated interior, illustration inside, "
|
||||
"photo, photorealistic, jpeg artifacts, cropped, out of frame, deformed"
|
||||
)
|
||||
|
||||
|
||||
def _inject_rembg(workflow: dict, model: str) -> dict:
|
||||
"""Inserta 'Image Rembg (Remove Background)' (transparency=True) entre VAEDecode y SaveImage.
|
||||
|
||||
Mismo helper que usan comfyui_build_ui_hud_workflow / comfyui_build_item_icon_workflow:
|
||||
el nodo recorta la silueta del panel de dialogo dejando alpha alrededor del
|
||||
borde. Repunta SaveImage.images a la salida del Rembg.
|
||||
"""
|
||||
wf = copy.deepcopy(workflow)
|
||||
vaedecode_id = next(
|
||||
(nid for nid, n in wf.items() if n.get("class_type") == "VAEDecode"), None
|
||||
)
|
||||
save_id = next((nid for nid, n in wf.items() if n.get("class_type") == "SaveImage"), None)
|
||||
if vaedecode_id is None or save_id is None:
|
||||
raise ValueError(
|
||||
"comfyui_build_dialogue_box_workflow: no se encontro VAEDecode/SaveImage para Rembg"
|
||||
)
|
||||
numeric = [int(k) for k in wf.keys() if str(k).isdigit()]
|
||||
rembg_id = str((max(numeric) + 1) if numeric else len(wf) + 1)
|
||||
wf[rembg_id] = {
|
||||
"class_type": "Image Rembg (Remove Background)",
|
||||
"inputs": {
|
||||
"images": [vaedecode_id, 0],
|
||||
"transparency": True,
|
||||
"model": model,
|
||||
"post_processing": False,
|
||||
"only_mask": False,
|
||||
"alpha_matting": False,
|
||||
"alpha_matting_foreground_threshold": 240,
|
||||
"alpha_matting_background_threshold": 10,
|
||||
"alpha_matting_erode_size": 10,
|
||||
"background_color": "none",
|
||||
},
|
||||
}
|
||||
wf[save_id]["inputs"]["images"] = [rembg_id, 0]
|
||||
return wf
|
||||
|
||||
|
||||
def comfyui_build_dialogue_box_workflow(
|
||||
box_style: str = "fantasy RPG dialogue box",
|
||||
*,
|
||||
shape: str = "rounded panel",
|
||||
checkpoint: str = "dreamshaper_8.safetensors",
|
||||
width: int = 768,
|
||||
height: int = 256,
|
||||
transparent: bool = True,
|
||||
seed: int = 0,
|
||||
lora: str | None = None,
|
||||
lora_strength: float = 1.0,
|
||||
rembg_model: str = "u2net",
|
||||
negative: str | None = None,
|
||||
steps: int = 28,
|
||||
cfg: float = 7.0,
|
||||
sampler_name: str = "dpmpp_2m",
|
||||
scheduler: str = "karras",
|
||||
filename_prefix: str = "dialogue_box",
|
||||
) -> dict:
|
||||
"""Construye el dict (API format) del workflow de una caja de dialogo de juego.
|
||||
|
||||
Args:
|
||||
box_style: descriptor del estilo del contenedor de dialogo (ej. "fantasy RPG
|
||||
dialogue box", "medieval fantasy dialogue box, wood and gold", "sci-fi
|
||||
terminal text box, neon glow", "visual novel text panel, soft pastel").
|
||||
Se inserta en un prompt scaffold de caja de dialogo. No puede estar vacio.
|
||||
shape: forma del panel (ej. "rounded panel", "rectangular banner", "scroll
|
||||
parchment", "stone tablet", "speech bubble"). Mantiene coherentes las
|
||||
cajas de un juego. keyword-only.
|
||||
checkpoint: checkpoint del servidor. 'dreamshaper_8.safetensors' (SD1.5,
|
||||
holgado en 8GB lowvram) por defecto; 'juggernaut_xl_v11.safetensors'
|
||||
para SDXL (mas VRAM, subir width/height). keyword-only.
|
||||
width: ancho del panel en px. Apaisado de caja de dialogo -> width > height.
|
||||
768 por defecto. keyword-only.
|
||||
height: alto del panel en px. 256 por defecto (panel bajo y ancho).
|
||||
keyword-only.
|
||||
transparent: si True inyecta Rembg y el PNG sale con alpha (fondo recortado
|
||||
alrededor del borde). Si False deja el panel opaco sobre fondo plano,
|
||||
recortable luego por el caller/pipeline. keyword-only.
|
||||
seed: semilla del KSampler. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'detail_tweaker_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.
|
||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime).
|
||||
Solo se usa si transparent=True. keyword-only.
|
||||
negative: prompt negativo. None usa el negativo por defecto pensado para la
|
||||
caja de dialogo (panel limpio, interior plano y vacio, sin texto ni
|
||||
personajes/escena). keyword-only.
|
||||
steps, cfg, sampler_name, scheduler, filename_prefix: parametros de
|
||||
generacion. keyword-only.
|
||||
|
||||
Returns:
|
||||
dict en API format listo para comfyui_submit_workflow: txt2img base apaisada
|
||||
con prompt scaffold de caja de dialogo ('{box_style}, {shape}, game UI
|
||||
dialogue box frame, ornate border, empty flat interior for text, plain
|
||||
background') + LoRA de estilo opcional + Rembg (si transparent). Es UNA caja;
|
||||
un set coherente -> llamar con el mismo box_style/shape/checkpoint/(lora). El
|
||||
texto de la conversacion lo renderiza el motor sobre el interior plano, no
|
||||
este workflow.
|
||||
|
||||
Raises:
|
||||
ValueError: si box_style esta vacio, o si la base no tiene VAEDecode/SaveImage
|
||||
donde inyectar el Rembg (propagado por el helper).
|
||||
"""
|
||||
from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow
|
||||
|
||||
if not box_style or not box_style.strip():
|
||||
raise ValueError(
|
||||
"comfyui_build_dialogue_box_workflow: 'box_style' no puede estar vacio"
|
||||
)
|
||||
|
||||
lora_strength = max(0.0, min(2.0, float(lora_strength)))
|
||||
neg = _DIALOGUE_NEGATIVE if negative is None else negative
|
||||
|
||||
# Prompt scaffold de caja de dialogo: panel apaisado con borde decorativo y un
|
||||
# interior PLANO y VACIO reservado para el texto que pone el motor de juego.
|
||||
positive = (
|
||||
f"{box_style.strip()}, {shape}, game UI dialogue box frame, "
|
||||
"ornate border, empty flat interior for text, plain background"
|
||||
)
|
||||
|
||||
wf = comfyui_build_txt2img_workflow(
|
||||
checkpoint,
|
||||
positive,
|
||||
neg,
|
||||
steps=steps,
|
||||
cfg=cfg,
|
||||
width=width,
|
||||
height=height,
|
||||
seed=seed,
|
||||
sampler_name=sampler_name,
|
||||
scheduler=scheduler,
|
||||
filename_prefix=filename_prefix,
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
if transparent:
|
||||
wf = _inject_rembg(wf, rembg_model)
|
||||
|
||||
return wf
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import json
|
||||
|
||||
wf = comfyui_build_dialogue_box_workflow(
|
||||
"medieval fantasy dialogue box, wood and gold",
|
||||
shape="rounded panel",
|
||||
transparent=True,
|
||||
seed=42,
|
||||
)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"nodes": list(wf),
|
||||
"classes": sorted({n["class_type"] for n in wf.values()}),
|
||||
},
|
||||
indent=2,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,109 @@
|
||||
"""Tests offline de comfyui_build_dialogue_box_workflow (estructura del dict, sin GPU)."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from ml.comfyui_build_dialogue_box_workflow import ( # noqa: E402
|
||||
comfyui_build_dialogue_box_workflow,
|
||||
)
|
||||
|
||||
|
||||
def _classes(wf):
|
||||
return sorted({n["class_type"] for n in wf.values()})
|
||||
|
||||
|
||||
def _by_class(wf, cls):
|
||||
return [n for n in wf.values() if n["class_type"] == cls]
|
||||
|
||||
|
||||
def _id_of(wf, cls):
|
||||
return next(nid for nid, n in wf.items() if n["class_type"] == cls)
|
||||
|
||||
|
||||
def test_golden_transparent_recipe():
|
||||
wf = comfyui_build_dialogue_box_workflow(
|
||||
"medieval fantasy dialogue box, wood and gold", transparent=True, seed=42
|
||||
)
|
||||
cls = _classes(wf)
|
||||
# Cadena base txt2img + Rembg para alpha.
|
||||
assert "CheckpointLoaderSimple" in cls
|
||||
assert "KSampler" in cls
|
||||
assert "VAEDecode" in cls
|
||||
assert "SaveImage" in cls
|
||||
assert "Image Rembg (Remove Background)" in cls
|
||||
# El box_style aparece en el prompt positivo, con el scaffold de caja de dialogo.
|
||||
pos = next(
|
||||
n for n in wf.values()
|
||||
if n["class_type"] == "CLIPTextEncode"
|
||||
and "medieval fantasy dialogue box" in n["inputs"]["text"]
|
||||
)
|
||||
assert "game UI dialogue box frame" in pos["inputs"]["text"]
|
||||
assert "ornate border" in pos["inputs"]["text"]
|
||||
assert "empty flat interior for text" in pos["inputs"]["text"]
|
||||
assert "plain background" in pos["inputs"]["text"]
|
||||
# SaveImage toma la imagen del Rembg (no del VAEDecode).
|
||||
rembg_id = _id_of(wf, "Image Rembg (Remove Background)")
|
||||
save = next(n for n in wf.values() if n["class_type"] == "SaveImage")
|
||||
assert save["inputs"]["images"] == [rembg_id, 0]
|
||||
assert _by_class(wf, "Image Rembg (Remove Background)")[0]["inputs"]["transparency"] is True
|
||||
|
||||
|
||||
def test_edge_opaque_no_rembg():
|
||||
wf = comfyui_build_dialogue_box_workflow("sci-fi text box", transparent=False)
|
||||
assert "Image Rembg (Remove Background)" not in _classes(wf)
|
||||
# SaveImage toma del VAEDecode directamente.
|
||||
vd_id = _id_of(wf, "VAEDecode")
|
||||
save = next(n for n in wf.values() if n["class_type"] == "SaveImage")
|
||||
assert save["inputs"]["images"] == [vd_id, 0]
|
||||
|
||||
|
||||
def test_edge_landscape_dims_reflected():
|
||||
wf = comfyui_build_dialogue_box_workflow("rpg dialogue box", width=896, height=224)
|
||||
latent = _by_class(wf, "EmptyLatentImage")[0]["inputs"]
|
||||
assert latent["width"] == 896
|
||||
assert latent["height"] == 224
|
||||
# Apaisado: ancho mayor que alto.
|
||||
assert latent["width"] > latent["height"]
|
||||
|
||||
|
||||
def test_edge_shape_in_prompt():
|
||||
wf = comfyui_build_dialogue_box_workflow(
|
||||
"visual novel text panel", shape="scroll parchment", transparent=False
|
||||
)
|
||||
pos = next(
|
||||
n for n in wf.values()
|
||||
if n["class_type"] == "CLIPTextEncode"
|
||||
and "visual novel text panel" in n["inputs"]["text"]
|
||||
)
|
||||
assert "scroll parchment" in pos["inputs"]["text"]
|
||||
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_dialogue_box_workflow(
|
||||
"fantasy dialogue box",
|
||||
lora="detail_tweaker_sd15.safetensors",
|
||||
lora_strength=0.9,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "detail_tweaker_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
def test_error_empty_box_style():
|
||||
try:
|
||||
comfyui_build_dialogue_box_workflow(" ")
|
||||
assert False
|
||||
except ValueError as e:
|
||||
assert "box_style" in str(e)
|
||||
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_dialogue_box_workflow(
|
||||
"stone tablet dialogue box", lora="detail_tweaker_sd15.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_dialogue_box_workflow(
|
||||
"stone tablet dialogue box", lora="detail_tweaker_sd15.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
Reference in New Issue
Block a user