feat(ml): LoRAs con prefijo de arquitectura (SD15_/SDXL_/FLUX_) + refs actualizadas
Mueve el indicador de arquitectura del SUFIJO al PREFIJO del nombre de cada LoRA para que el dropdown del LoraLoader muestre de inmediato que LoRA casa con que checkpoint (evita el shape mismatch SD1.5 vs SDXL que crashea ComfyUI). - 20 LoRAs renombradas en disco (15 SD15/SDXL en /mnt/2tb, 5 FLUX en ~/ComfyUI), mapa de reversion en ~/ComfyUI/models/loras/_rename_map.json. - Refs actualizadas en builders gamedev-2d, style presets, pipelines, tests y docs/capabilities. Defaults hardcodeados (pixel-art, lcm-lora, etc.) apuntan a los nombres con prefijo. - Ejemplos genericos en docstrings normalizados a la convencion de prefijo. - comfyui_replicate_civitai_oneshot::_norm ignora el token de arquitectura al comparar, robusto al reordenado (sufijo civitai vs prefijo instalado). Refs a repos HuggingFace (nerijs/pixel-art-xl) y checkpoints (juggernaut_xl_v11) preservados. Verificado: dropdown LoraLoader con prefijos + generacion real pixel-art OK + tests comfyui verdes (481 ml + 26 pipelines). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,7 +41,7 @@ def test_golden_kwargs_spreadable_into_builder():
|
||||
assert "KSampler" in cls
|
||||
# El LoRA watercolor del preset aparece en el grafo.
|
||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||
assert loras and loras[0]["inputs"]["lora_name"] == "watercolor_style_sd15.safetensors"
|
||||
assert loras and loras[0]["inputs"]["lora_name"] == "SD15_watercolor_style.safetensors"
|
||||
|
||||
|
||||
def test_edge_style_override():
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Fija el mismo seed en la familia de tiers del mismo logro para que coincidan en composicion. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'detail_tweaker_sd15.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.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
|
||||
|
||||
@@ -169,7 +169,7 @@ def comfyui_build_achievement_badge_workflow(
|
||||
seed: semilla del KSampler. Fija el mismo seed en la familia de tiers del mismo
|
||||
logro para que coincidan en composicion. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'detail_tweaker_sd15.safetensors'). None = sin LoRA. keyword-only.
|
||||
'SD15_detail_tweaker.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
|
||||
|
||||
@@ -131,11 +131,11 @@ def test_edge_badge_reflected():
|
||||
def test_edge_lora_injected():
|
||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||
wf = comfyui_build_achievement_badge_workflow(
|
||||
"collector", lora="detail_tweaker_sd15.safetensors", lora_strength=0.8
|
||||
"collector", lora="SD15_detail_tweaker.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "detail_tweaker_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.8)
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_dark_fantasy.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
|
||||
|
||||
@@ -154,7 +154,7 @@ def comfyui_build_asset_variant_workflow(
|
||||
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.
|
||||
'SD15_dark_fantasy.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',
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + mismo subject -> misma ilustracion. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'detail_tweaker_sd15.safetensors', 'anime_style_xl.safetensors'). None = sin LoRA. Encadena estilo coherente entre cartas. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.safetensors', 'SDXL_anime_style.safetensors'). None = sin LoRA. Encadena estilo coherente entre cartas. keyword-only."
|
||||
- name: lora_strength
|
||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||
- name: negative
|
||||
|
||||
@@ -113,7 +113,7 @@ def comfyui_build_card_art_workflow(
|
||||
seed: semilla del KSampler (y de la pasada hires). Misma seed + mismo
|
||||
subject -> misma ilustracion. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'detail_tweaker_sd15.safetensors', 'anime_style_xl.safetensors'). None =
|
||||
'SD15_detail_tweaker.safetensors', 'SDXL_anime_style.safetensors'). None =
|
||||
sin LoRA. Encadena estilo coherente entre cartas. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -94,13 +94,13 @@ def test_edge_card_style_in_prompt():
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_card_art_workflow(
|
||||
"a phoenix",
|
||||
lora="detail_tweaker_sd15.safetensors",
|
||||
lora="SD15_detail_tweaker.safetensors",
|
||||
lora_strength=0.9,
|
||||
hires=False,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "detail_tweaker_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
||||
ksampler = _by_class(wf, "KSampler")[0]
|
||||
|
||||
@@ -114,11 +114,11 @@ def test_edge_negative_isolates_decal():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_decal_overlay_workflow(
|
||||
"rust stain", lora="grunge_sd15.safetensors", lora_strength=0.8
|
||||
"rust stain", lora="SD15_grunge.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "grunge_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_grunge.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||
|
||||
|
||||
@@ -132,9 +132,9 @@ def test_error_empty_decal():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_decal_overlay_workflow(
|
||||
"blood splatter", on_black=True, lora="grunge_sd15.safetensors", seed=7
|
||||
"blood splatter", on_black=True, lora="SD15_grunge.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_decal_overlay_workflow(
|
||||
"blood splatter", on_black=True, lora="grunge_sd15.safetensors", seed=7
|
||||
"blood splatter", on_black=True, lora="SD15_grunge.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.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
|
||||
@@ -72,7 +72,7 @@ wf = comfyui_build_dialogue_box_workflow(
|
||||
# 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)
|
||||
# lora="SD15_detail_tweaker.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.
|
||||
```
|
||||
|
||||
@@ -141,7 +141,7 @@ def comfyui_build_dialogue_box_workflow(
|
||||
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.
|
||||
'SD15_detail_tweaker.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).
|
||||
|
||||
@@ -82,12 +82,12 @@ def test_edge_shape_in_prompt():
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_dialogue_box_workflow(
|
||||
"fantasy dialogue box",
|
||||
lora="detail_tweaker_sd15.safetensors",
|
||||
lora="SD15_detail_tweaker.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"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -101,9 +101,9 @@ def test_error_empty_box_style():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_dialogue_box_workflow(
|
||||
"stone tablet dialogue box", lora="detail_tweaker_sd15.safetensors", seed=7
|
||||
"stone tablet dialogue box", lora="SD15_detail_tweaker.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_dialogue_box_workflow(
|
||||
"stone tablet dialogue box", lora="detail_tweaker_sd15.safetensors", seed=7
|
||||
"stone tablet dialogue box", lora="SD15_detail_tweaker.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -32,7 +32,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler (y del sampler del FaceDetailer). Misma seed + mismo character/ref_face -> mismo personaje; variar solo expression mantiene la identidad y cambia la cara. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'anime_lineart_sd15.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_anime_lineart.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: weight
|
||||
|
||||
@@ -119,7 +119,7 @@ def comfyui_build_emote_workflow(
|
||||
mismo character/ref_face -> mismo personaje; variar solo expression
|
||||
mantiene la identidad y cambia la cara. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'anime_lineart_sd15.safetensors'). None = sin LoRA. keyword-only.
|
||||
'SD15_anime_lineart.safetensors'). None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
weight: peso del IPAdapter-FaceID (solo si ref_face). 0.85 = parecido alto;
|
||||
|
||||
@@ -138,13 +138,13 @@ def test_edge_lora_reflected():
|
||||
wf = comfyui_build_emote_workflow(
|
||||
"a dark sorceress",
|
||||
"smug",
|
||||
lora="anime_lineart_sd15.safetensors",
|
||||
lora="SD15_anime_lineart.safetensors",
|
||||
lora_strength=0.8,
|
||||
facedetailer=False,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "anime_lineart_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_anime_lineart.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||
|
||||
|
||||
@@ -176,13 +176,13 @@ def test_determinism():
|
||||
a = comfyui_build_emote_workflow(
|
||||
"a knight woman with red hair",
|
||||
"happy, smiling",
|
||||
lora="anime_lineart_sd15.safetensors",
|
||||
lora="SD15_anime_lineart.safetensors",
|
||||
seed=7,
|
||||
)
|
||||
b = comfyui_build_emote_workflow(
|
||||
"a knight woman with red hair",
|
||||
"happy, smiling",
|
||||
lora="anime_lineart_sd15.safetensors",
|
||||
lora="SD15_anime_lineart.safetensors",
|
||||
seed=7,
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Misma seed + misma criatura/style -> misma figura; variar solo `variant` da variantes coherentes. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo/criatura opcional en models/loras (ej. 'dark_fantasy_sd15.safetensors', 'monster_design_xl.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo/criatura opcional en models/loras (ej. 'SD15_dark_fantasy.safetensors', 'SDXL_monster_design.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
|
||||
|
||||
@@ -147,7 +147,7 @@ def comfyui_build_enemy_creature_workflow(
|
||||
seed: semilla del KSampler. Misma seed + misma criatura/style -> misma
|
||||
figura; variar solo `variant` da las variantes coherentes. keyword-only.
|
||||
lora: LoRA de estilo/criatura opcional en models/loras (ej.
|
||||
'dark_fantasy_sd15.safetensors', 'monster_design_xl.safetensors'). None =
|
||||
'SD15_dark_fantasy.safetensors', 'SDXL_monster_design.safetensors'). None =
|
||||
sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -87,11 +87,11 @@ def test_edge_style_in_prompt():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_enemy_creature_workflow(
|
||||
"shadow wraith", lora="dark_fantasy_sd15.safetensors", lora_strength=0.9
|
||||
"shadow wraith", lora="SD15_dark_fantasy.safetensors", lora_strength=0.9
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "dark_fantasy_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_dark_fantasy.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -105,9 +105,9 @@ def test_error_empty_creature():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_enemy_creature_workflow(
|
||||
"fire dragon", variant="elite", lora="monster_design_xl.safetensors", seed=7
|
||||
"fire dragon", variant="elite", lora="SDXL_monster_design.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_enemy_creature_workflow(
|
||||
"fire dragon", variant="elite", lora="monster_design_xl.safetensors", seed=7
|
||||
"fire dragon", variant="elite", lora="SDXL_monster_design.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Misma seed + mismo plant/view/style -> misma planta. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'stylized_nature_sd15.safetensors', 'painterly_plants_xl.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_stylized_nature.safetensors', 'SDXL_painterly_plants.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
|
||||
|
||||
@@ -161,7 +161,7 @@ def comfyui_build_foliage_set_workflow(
|
||||
seed: semilla del KSampler. Misma seed + mismo plant/view/style -> misma
|
||||
planta. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'stylized_nature_sd15.safetensors', 'painterly_plants_xl.safetensors').
|
||||
'SD15_stylized_nature.safetensors', 'SDXL_painterly_plants.safetensors').
|
||||
None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -111,7 +111,7 @@ def test_edge_negative_rejects_manmade_and_buildings():
|
||||
def test_edge_lora_present():
|
||||
"""lora -> LoraLoader presente con la fuerza pasada."""
|
||||
wf = comfyui_build_foliage_set_workflow(
|
||||
"a cluster of red flowers", lora="stylized_nature_sd15.safetensors",
|
||||
"a cluster of red flowers", lora="SD15_stylized_nature.safetensors",
|
||||
lora_strength=0.8,
|
||||
)
|
||||
assert "LoraLoader" in _classes(wf)
|
||||
|
||||
@@ -33,7 +33,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_dark_fantasy.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: mode
|
||||
|
||||
@@ -279,7 +279,7 @@ def comfyui_build_inpaint_asset_workflow(
|
||||
los assets del set ya salen a 512). Un int reescala AMBAS a size x size de
|
||||
forma consistente. Solo aplica al modo vae_encode. keyword-only.
|
||||
seed: semilla del KSampler. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej. 'dark_fantasy_sd15.safetensors').
|
||||
lora: LoRA de estilo opcional en models/loras (ej. 'SD15_dark_fantasy.safetensors').
|
||||
None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -107,7 +107,7 @@ La referencia se sube primero a `input/` del servidor (LoadImage la lee por nomb
|
||||
registra la carpeta `models/ipadapter`; si los modelos viven en otra ruta (ej.
|
||||
`/mnt/2tb`), esa clave los mapea. Sin ella `ipadapter_file` sale vacio.
|
||||
- **faceid usa insightface (`buffalo_l`) + la LoRA FaceID.** El UnifiedLoaderFaceID
|
||||
carga la LoRA `ip-adapter-faceid-plusv2_sd15_lora.safetensors` (debe estar en
|
||||
carga la LoRA `SD15_ip-adapter-faceid-plusv2_lora.safetensors` (debe estar en
|
||||
`models/loras/`). `provider='CPU'` por defecto: insightface en CPU no compite por
|
||||
los 8GB de VRAM; pon `'CUDA'` solo si tienes onnxruntime-gpu instalado.
|
||||
- **La referencia debe existir en `input/`.** Es un nombre de archivo, no una ruta:
|
||||
|
||||
@@ -5,8 +5,8 @@ lang: py
|
||||
domain: ml
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "def comfyui_build_isometric_workflow(positive: str, negative: str = \"perspective, vanishing point, blurry, low quality\", *, ckpt_name: str = \"dreamshaper_8.safetensors\", iso_lora: str = \"isometric_game_assets_sd15.safetensors\", lora_strength: float = 0.9, grid_image: str | None = None, controlnet_name: str = \"control_v11p_sd15_canny_fp16.safetensors\", controlnet_strength: float = 0.6, steps: int = 28, cfg: float = 6.0, width: int = 1024, height: int = 1024, seed: int = 0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", filename_prefix: str = \"isometric\") -> dict"
|
||||
description: "Construye el dict (API format) de un workflow ComfyUI isometrico: txt2img + LoRA isometrica (isometric_game_assets_sd15) que impone el angulo 2:1, con ControlNet grid opcional (plantilla de rejilla iso preprocesada) para reforzar el layout. Compone comfyui_build_txt2img_workflow + comfyui_inject_lora (+ comfyui_inject_controlnet si grid_image). Pura, sin red ni I/O. class_types verificados contra /object_info."
|
||||
signature: "def comfyui_build_isometric_workflow(positive: str, negative: str = \"perspective, vanishing point, blurry, low quality\", *, ckpt_name: str = \"dreamshaper_8.safetensors\", iso_lora: str = \"SD15_isometric_game_assets.safetensors\", lora_strength: float = 0.9, grid_image: str | None = None, controlnet_name: str = \"control_v11p_sd15_canny_fp16.safetensors\", controlnet_strength: float = 0.6, steps: int = 28, cfg: float = 6.0, width: int = 1024, height: int = 1024, seed: int = 0, sampler_name: str = \"dpmpp_2m\", scheduler: str = \"karras\", filename_prefix: str = \"isometric\") -> dict"
|
||||
description: "Construye el dict (API format) de un workflow ComfyUI isometrico: txt2img + LoRA isometrica (SD15_isometric_game_assets) que impone el angulo 2:1, con ControlNet grid opcional (plantilla de rejilla iso preprocesada) para reforzar el layout. Compone comfyui_build_txt2img_workflow + comfyui_inject_lora (+ comfyui_inject_controlnet si grid_image). Pura, sin red ni I/O. class_types verificados contra /object_info."
|
||||
tags: [comfyui, ml, gamedev-2d, isometric, tile, workflow, stable-diffusion]
|
||||
uses_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_inject_lora_py_ml, comfyui_inject_controlnet_py_ml]
|
||||
uses_types: []
|
||||
@@ -22,7 +22,7 @@ params:
|
||||
- name: ckpt_name
|
||||
desc: "Checkpoint base. Default 'dreamshaper_8.safetensors' (SD1.5 holgado, casa con la LoRA iso SD1.5). keyword-only."
|
||||
- name: iso_lora
|
||||
desc: "LoRA isometrica en models/loras. Default 'isometric_game_assets_sd15.safetensors'. keyword-only."
|
||||
desc: "LoRA isometrica en models/loras. Default 'SD15_isometric_game_assets.safetensors'. keyword-only."
|
||||
- name: lora_strength
|
||||
desc: "Fuerza de la LoRA iso sobre model y clip (recomendado 0.9). keyword-only."
|
||||
- name: grid_image
|
||||
@@ -86,7 +86,7 @@ el prompt se desvíe del ángulo y quieras forzar la rejilla. Para una textura i
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Requiere la LoRA `isometric_game_assets_sd15.safetensors` en models/loras**
|
||||
- **Requiere la LoRA `SD15_isometric_game_assets.safetensors` en models/loras**
|
||||
(ya presente). Es SD1.5: usa un checkpoint SD1.5 (`dreamshaper_8`).
|
||||
- **`comfyui_inject_controlnet` NO preprocesa**: `grid_image` debe ser una imagen
|
||||
de control ya en line-art/canny limpio. Si partes de un render, preprocésala
|
||||
|
||||
@@ -5,7 +5,7 @@ La proyeccion isometrica 2:1 no necesita node nuevo: es composicion pura (report
|
||||
|
||||
1. LoRA isometrica (via principal): impone el angulo 2:1 y el look de tile. Se
|
||||
inyecta con comfyui_inject_lora sobre la base txt2img. LoRA instalada:
|
||||
isometric_game_assets_sd15.safetensors (SD1.5, holgada en 8GB).
|
||||
SD15_isometric_game_assets.safetensors (SD1.5, holgada en 8GB).
|
||||
2. ControlNet grid (refuerzo opcional): una plantilla de rejilla isometrica
|
||||
(rombos 2:1) ya preprocesada (canny/lineart) fuerza el layout. Se inyecta con
|
||||
comfyui_inject_controlnet (legacy ControlNetApply; basta para un grid guia).
|
||||
@@ -35,7 +35,7 @@ def comfyui_build_isometric_workflow(
|
||||
negative: str = "perspective, vanishing point, blurry, low quality",
|
||||
*,
|
||||
ckpt_name: str = "dreamshaper_8.safetensors",
|
||||
iso_lora: str = "isometric_game_assets_sd15.safetensors",
|
||||
iso_lora: str = "SD15_isometric_game_assets.safetensors",
|
||||
lora_strength: float = 0.9,
|
||||
grid_image: str | None = None,
|
||||
controlnet_name: str = "control_v11p_sd15_canny_fp16.safetensors",
|
||||
@@ -59,7 +59,7 @@ def comfyui_build_isometric_workflow(
|
||||
ckpt_name: checkpoint base (default 'dreamshaper_8.safetensors', SD1.5
|
||||
holgado y casa con la LoRA iso SD1.5). keyword-only.
|
||||
iso_lora: LoRA isometrica en models/loras
|
||||
(default 'isometric_game_assets_sd15.safetensors').
|
||||
(default 'SD15_isometric_game_assets.safetensors').
|
||||
lora_strength: fuerza de la LoRA iso sobre model y clip (recomendado 0.9).
|
||||
grid_image: nombre de una plantilla de rejilla isometrica ya preprocesada
|
||||
(line-art/canny) en input/ del servidor. Si se pasa, inyecta un
|
||||
|
||||
@@ -15,7 +15,7 @@ def test_golden_iso_lora_no_controlnet():
|
||||
wf = comfyui_build_isometric_workflow("isometric house, game asset")
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "isometric_game_assets_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_isometric_game_assets.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
# Sin grid_image -> sin ControlNet.
|
||||
assert len(_by_class(wf, "ControlNetApply")) == 0
|
||||
|
||||
@@ -28,7 +28,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'detail_tweaker_sd15.safetensors', 'isometric_game_assets_sd15.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.safetensors', 'SD15_isometric_game_assets.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
|
||||
@@ -69,7 +69,7 @@ wf = comfyui_build_item_icon_workflow(
|
||||
# Set coherente: misma firma de estilo para cada item del inventario.
|
||||
# for it in ["iron sword", "gold ring", "ancient book", "wooden shield"]:
|
||||
# wf = comfyui_build_item_icon_workflow(it, style="hand-painted RPG icon",
|
||||
# lora="detail_tweaker_sd15.safetensors", seed=42)
|
||||
# lora="SD15_detail_tweaker.safetensors", seed=42)
|
||||
# comfyui_submit_workflow(wf) # -> comfyui_wait_result -> comfyui_fetch_output_image
|
||||
# Contact-sheet del set: montar los PNG resultantes con comfyui_build_grid.
|
||||
```
|
||||
|
||||
@@ -121,7 +121,7 @@ def comfyui_build_item_icon_workflow(
|
||||
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', 'isometric_game_assets_sd15.safetensors').
|
||||
'SD15_detail_tweaker.safetensors', 'SD15_isometric_game_assets.safetensors').
|
||||
None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -73,11 +73,11 @@ def test_edge_style_in_prompt():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_item_icon_workflow(
|
||||
"magic shield", lora="detail_tweaker_sd15.safetensors", lora_strength=0.9
|
||||
"magic shield", lora="SD15_detail_tweaker.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"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -90,6 +90,6 @@ def test_error_empty_item():
|
||||
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_item_icon_workflow("emerald gem", lora="detail_tweaker_sd15.safetensors", seed=7)
|
||||
b = comfyui_build_item_icon_workflow("emerald gem", lora="detail_tweaker_sd15.safetensors", seed=7)
|
||||
a = comfyui_build_item_icon_workflow("emerald gem", lora="SD15_detail_tweaker.safetensors", seed=7)
|
||||
b = comfyui_build_item_icon_workflow("emerald gem", lora="SD15_detail_tweaker.safetensors", seed=7)
|
||||
assert a == b
|
||||
|
||||
@@ -39,7 +39,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_dark_fantasy.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: negative
|
||||
|
||||
@@ -169,7 +169,7 @@ def comfyui_build_outpaint_asset_workflow(
|
||||
costura. Default 0 (el feathering del pad suele bastar). Se clampa a [0, 64]
|
||||
(limite de VAEEncodeForInpaint). keyword-only.
|
||||
seed: semilla del KSampler. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej. 'dark_fantasy_sd15.safetensors').
|
||||
lora: LoRA de estilo opcional en models/loras (ej. 'SD15_dark_fantasy.safetensors').
|
||||
None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -123,11 +123,11 @@ def test_edge_negative_isolates_single_particle():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_particle_texture_workflow(
|
||||
"glowing flare", lora="vfx_sd15.safetensors", lora_strength=0.8
|
||||
"glowing flare", lora="SD15_vfx.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "vfx_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_vfx.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||
|
||||
|
||||
@@ -141,9 +141,9 @@ def test_error_empty_particle():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_particle_texture_workflow(
|
||||
"spark", soft=False, lora="vfx_sd15.safetensors", seed=7
|
||||
"spark", soft=False, lora="SD15_vfx.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_particle_texture_workflow(
|
||||
"spark", soft=False, lora="vfx_sd15.safetensors", seed=7
|
||||
"spark", soft=False, lora="SD15_vfx.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -5,8 +5,8 @@ lang: py
|
||||
domain: ml
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "def comfyui_build_pixelart_workflow(positive: str, negative: str = \"blurry, jpeg artifacts, gradient, smooth shading, anti-aliasing\", *, ckpt_name: str = \"juggernaut_xl_v11.safetensors\", pixel_lora: str = \"pixel-art-xl.safetensors\", lora_strength: float = 1.2, use_lcm: bool = True, lcm_lora: str = \"lcm-lora-sdxl.safetensors\", lcm_strength: float = 1.0, steps: int | None = None, cfg: float | None = None, width: int = 1024, height: int = 1024, seed: int = 0, sampler_name: str | None = None, scheduler: str | None = None, filename_prefix: str = \"pixelart\") -> dict"
|
||||
description: "Construye el dict (API format) del workflow ComfyUI de pixel-art Fase 1: SDXL base + LoRA pixel-art-xl (nerijs), opcionalmente con LCM-LoRA para 8 steps. Compone comfyui_build_txt2img_workflow + comfyui_inject_multi_lora. El pixel-perfect (Fase 2) lo hace comfyui_pixelize_image, no este workflow. Pura, sin red ni I/O. class_types verificados contra /object_info (8GB lowvram)."
|
||||
signature: "def comfyui_build_pixelart_workflow(positive: str, negative: str = \"blurry, jpeg artifacts, gradient, smooth shading, anti-aliasing\", *, ckpt_name: str = \"juggernaut_xl_v11.safetensors\", pixel_lora: str = \"SDXL_pixel-art.safetensors\", lora_strength: float = 1.2, use_lcm: bool = True, lcm_lora: str = \"SDXL_lcm-lora.safetensors\", lcm_strength: float = 1.0, steps: int | None = None, cfg: float | None = None, width: int = 1024, height: int = 1024, seed: int = 0, sampler_name: str | None = None, scheduler: str | None = None, filename_prefix: str = \"pixelart\") -> dict"
|
||||
description: "Construye el dict (API format) del workflow ComfyUI de pixel-art Fase 1: SDXL base + LoRA SDXL_pixel-art (nerijs), opcionalmente con LCM-LoRA para 8 steps. Compone comfyui_build_txt2img_workflow + comfyui_inject_multi_lora. El pixel-perfect (Fase 2) lo hace comfyui_pixelize_image, no este workflow. Pura, sin red ni I/O. class_types verificados contra /object_info (8GB lowvram)."
|
||||
tags: [comfyui, ml, gamedev-2d, pixelart, workflow, stable-diffusion, sdxl]
|
||||
uses_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_inject_multi_lora_py_ml]
|
||||
uses_types: []
|
||||
@@ -20,15 +20,15 @@ params:
|
||||
- name: negative
|
||||
desc: "Prompt negativo. Por defecto evita blur/gradientes/anti-alias que estropean el look pixel."
|
||||
- name: ckpt_name
|
||||
desc: "Checkpoint SDXL base. Default 'juggernaut_xl_v11.safetensors' (el SDXL instalado; pixel-art-xl es LoRA SDXL). keyword-only."
|
||||
desc: "Checkpoint SDXL base. Default 'juggernaut_xl_v11.safetensors' (el SDXL instalado; SDXL_pixel-art es LoRA SDXL). keyword-only."
|
||||
- name: pixel_lora
|
||||
desc: "Archivo de la LoRA de estilo pixel-art en models/loras. Default 'pixel-art-xl.safetensors'. keyword-only."
|
||||
desc: "Archivo de la LoRA de estilo pixel-art en models/loras. Default 'SDXL_pixel-art.safetensors'. keyword-only."
|
||||
- name: lora_strength
|
||||
desc: "Fuerza de pixel-art-xl sobre model y clip (recomendado 1.2). Se clampa a [0.0, 2.0]. keyword-only."
|
||||
desc: "Fuerza de SDXL_pixel-art sobre model y clip (recomendado 1.2). Se clampa a [0.0, 2.0]. keyword-only."
|
||||
- name: use_lcm
|
||||
desc: "Si True encadena LCM-LoRA SDXL y usa defaults rapidos (8 steps, cfg 1.5, sampler 'lcm', scheduler 'sgm_uniform'); si False usa defaults SDXL normales (25 steps, cfg 7, 'euler'/'normal'). keyword-only."
|
||||
- name: lcm_lora
|
||||
desc: "Archivo de la LCM-LoRA SDXL en models/loras (solo si use_lcm). Default 'lcm-lora-sdxl.safetensors'. keyword-only."
|
||||
desc: "Archivo de la LCM-LoRA SDXL en models/loras (solo si use_lcm). Default 'SDXL_lcm-lora.safetensors'. keyword-only."
|
||||
- name: lcm_strength
|
||||
desc: "Fuerza de la LCM-LoRA sobre model y clip (recomendado 1.0). keyword-only."
|
||||
- name: steps
|
||||
@@ -47,9 +47,9 @@ params:
|
||||
desc: "Scheduler del KSampler. None = default del modo ('sgm_uniform' con LCM, 'normal' sin). keyword-only."
|
||||
- name: filename_prefix
|
||||
desc: "Prefijo del PNG que SaveImage escribe en output/. keyword-only."
|
||||
output: "dict en API format listo para comfyui_submit_workflow: CheckpointLoaderSimple + 1 LoraLoader (pixel-art-xl) o 2 (+ lcm-lora-sdxl si use_lcm) + KSampler con params del modo + SaveImage."
|
||||
output: "dict en API format listo para comfyui_submit_workflow: CheckpointLoaderSimple + 1 LoraLoader (SDXL_pixel-art) o 2 (+ SDXL_lcm-lora si use_lcm) + KSampler con params del modo + SaveImage."
|
||||
tested: true
|
||||
tests: ["golden use_lcm=True: 2 LoraLoader (pixel-art-xl@1.2, lcm@1.0) + KSampler steps 8/cfg 1.5/sampler lcm/sgm_uniform", "edge use_lcm=False: 1 LoraLoader + KSampler steps 25/cfg 7/euler/normal", "edge overrides steps/cfg + clamp lora_strength a 2.0", "error positive vacio -> ValueError", "determinismo"]
|
||||
tests: ["golden use_lcm=True: 2 LoraLoader (SDXL_pixel-art@1.2, lcm@1.0) + KSampler steps 8/cfg 1.5/sampler lcm/sgm_uniform", "edge use_lcm=False: 1 LoraLoader + KSampler steps 25/cfg 7/euler/normal", "edge overrides steps/cfg + clamp lora_strength a 2.0", "error positive vacio -> ValueError", "determinismo"]
|
||||
test_file_path: "python/functions/ml/comfyui_build_pixelart_workflow_test.py"
|
||||
file_path: "python/functions/ml/comfyui_build_pixelart_workflow.py"
|
||||
---
|
||||
@@ -61,7 +61,7 @@ import sys, os
|
||||
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
|
||||
from ml.comfyui_build_pixelart_workflow import comfyui_build_pixelart_workflow
|
||||
|
||||
# Fase 1: generar el crudo pixel-art (SDXL + pixel-art-xl + LCM, 8 steps).
|
||||
# Fase 1: generar el crudo pixel-art (SDXL + SDXL_pixel-art + LCM, 8 steps).
|
||||
wf = comfyui_build_pixelart_workflow(
|
||||
"isometric tiny house, pixel, 32x32 style, vibrant colors",
|
||||
use_lcm=True,
|
||||
@@ -87,9 +87,9 @@ Para tilesets, genera cada tile por separado y ensambla con `comfyui_build_grid`
|
||||
no lo pegues en la UI.
|
||||
- **No produce pixel-perfect por sí solo**: deja pixeles irregulares y cientos de
|
||||
colores. El pixel-perfect es post-proceso (`comfyui_pixelize_image`, CPU/PIL).
|
||||
- `use_lcm=True` requiere `lcm-lora-sdxl.safetensors` en models/loras y el sampler
|
||||
- `use_lcm=True` requiere `SDXL_lcm-lora.safetensors` en models/loras y el sampler
|
||||
`lcm`; ambos verificados presentes. Da iteración rápida (8 steps) en 8GB.
|
||||
- `ckpt_name` debe ser un checkpoint SDXL (pixel-art-xl es LoRA SDXL). Default
|
||||
- `ckpt_name` debe ser un checkpoint SDXL (SDXL_pixel-art es LoRA SDXL). Default
|
||||
`juggernaut_xl_v11` (no existe `sd_xl_base_1.0` instalado). SDXL en 8GB corre con
|
||||
`--lowvram`; la Fase 2 es CPU y no toca VRAM.
|
||||
- Función pura: no valida contra el server. Si una LoRA/checkpoint falta, el HTTP
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
"""Construye un workflow ComfyUI de pixel-art (SDXL + LoRA pixel-art-xl) en API format.
|
||||
"""Construye un workflow ComfyUI de pixel-art (SDXL + LoRA SDXL_pixel-art) en API format.
|
||||
|
||||
Fase 1 del pipeline pixel-art (ver report 0135): genera el *look* pixel-art con
|
||||
SDXL base + la LoRA `pixel-art-xl` (nerijs), opcionalmente acelerada con la
|
||||
SDXL base + la LoRA `SDXL_pixel-art` (nerijs), opcionalmente acelerada con la
|
||||
LCM-LoRA SDXL para iterar en 8 steps. El resultado todavia tiene pixeles de
|
||||
tamano irregular y cientos de colores: el pixel-perfect (Fase 2) lo hace
|
||||
`comfyui_pixelize_image` (downscale nearest + cuantizacion), NO este workflow.
|
||||
|
||||
Compone funciones existentes del registry, no reescribe el grafo:
|
||||
- comfyui_build_txt2img_workflow -> base SDXL txt2img
|
||||
- comfyui_inject_multi_lora -> encadena pixel-art-xl (+ lcm-lora-sdxl)
|
||||
- comfyui_inject_multi_lora -> encadena SDXL_pixel-art (+ SDXL_lcm-lora)
|
||||
|
||||
class_types/params verificados contra /object_info del servidor (8GB lowvram):
|
||||
CheckpointLoaderSimple, LoraLoader, CLIPTextEncode, EmptyLatentImage,
|
||||
KSampler (sampler 'lcm', scheduler 'sgm_uniform' presentes), VAEDecode, SaveImage.
|
||||
LoRAs presentes en models/loras: pixel-art-xl.safetensors, lcm-lora-sdxl.safetensors.
|
||||
LoRAs presentes en models/loras: SDXL_pixel-art.safetensors, SDXL_lcm-lora.safetensors.
|
||||
|
||||
Funcion pura: sin red, sin I/O. Determinista para los mismos argumentos.
|
||||
"""
|
||||
@@ -34,10 +34,10 @@ def comfyui_build_pixelart_workflow(
|
||||
negative: str = "blurry, jpeg artifacts, gradient, smooth shading, anti-aliasing",
|
||||
*,
|
||||
ckpt_name: str = "juggernaut_xl_v11.safetensors",
|
||||
pixel_lora: str = "pixel-art-xl.safetensors",
|
||||
pixel_lora: str = "SDXL_pixel-art.safetensors",
|
||||
lora_strength: float = 1.2,
|
||||
use_lcm: bool = True,
|
||||
lcm_lora: str = "lcm-lora-sdxl.safetensors",
|
||||
lcm_lora: str = "SDXL_lcm-lora.safetensors",
|
||||
lcm_strength: float = 1.0,
|
||||
steps: int | None = None,
|
||||
cfg: float | None = None,
|
||||
@@ -56,9 +56,9 @@ def comfyui_build_pixelart_workflow(
|
||||
negative: prompt negativo (por defecto evita blur/gradientes/anti-alias,
|
||||
que estropean el look pixel).
|
||||
ckpt_name: checkpoint SDXL base (default 'juggernaut_xl_v11.safetensors',
|
||||
el SDXL instalado; pixel-art-xl es una LoRA SDXL). keyword-only.
|
||||
el SDXL instalado; SDXL_pixel-art es una LoRA SDXL). keyword-only.
|
||||
pixel_lora: archivo de la LoRA de estilo pixel-art en models/loras.
|
||||
lora_strength: fuerza de pixel-art-xl sobre model y clip (recomendado 1.2).
|
||||
lora_strength: fuerza de SDXL_pixel-art sobre model y clip (recomendado 1.2).
|
||||
Se clampa a [0.0, 2.0].
|
||||
use_lcm: si True encadena la LCM-LoRA SDXL y usa los defaults rapidos
|
||||
(8 steps, cfg 1.5, sampler 'lcm', scheduler 'sgm_uniform'); si False
|
||||
@@ -74,8 +74,8 @@ def comfyui_build_pixelart_workflow(
|
||||
|
||||
Returns:
|
||||
dict en API format listo para comfyui_submit_workflow, con el
|
||||
CheckpointLoaderSimple, 1 LoraLoader (pixel-art-xl) o 2 (pixel-art-xl +
|
||||
lcm-lora-sdxl si use_lcm), KSampler con los params del modo y SaveImage.
|
||||
CheckpointLoaderSimple, 1 LoraLoader (SDXL_pixel-art) o 2 (SDXL_pixel-art +
|
||||
SDXL_lcm-lora si use_lcm), KSampler con los params del modo y SaveImage.
|
||||
|
||||
Raises:
|
||||
ValueError: si positive esta vacio.
|
||||
|
||||
@@ -18,12 +18,12 @@ def _ksampler(wf):
|
||||
def test_golden_lcm_two_loras():
|
||||
wf = comfyui_build_pixelart_workflow("isometric house, pixel, 32x32 style", use_lcm=True)
|
||||
cls = _classes(wf)
|
||||
# Dos LoraLoader: pixel-art-xl + lcm-lora-sdxl.
|
||||
# Dos LoraLoader: SDXL_pixel-art + SDXL_lcm-lora.
|
||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||
assert len(loras) == 2
|
||||
names = {n["inputs"]["lora_name"] for n in loras}
|
||||
assert names == {"pixel-art-xl.safetensors", "lcm-lora-sdxl.safetensors"}
|
||||
px = next(n for n in loras if n["inputs"]["lora_name"] == "pixel-art-xl.safetensors")
|
||||
assert names == {"SDXL_pixel-art.safetensors", "SDXL_lcm-lora.safetensors"}
|
||||
px = next(n for n in loras if n["inputs"]["lora_name"] == "SDXL_pixel-art.safetensors")
|
||||
assert px["inputs"]["strength_model"] == 1.2
|
||||
# KSampler con defaults LCM.
|
||||
ks = _ksampler(wf)["inputs"]
|
||||
@@ -36,7 +36,7 @@ def test_edge_no_lcm_single_lora():
|
||||
wf = comfyui_build_pixelart_workflow("a pixel sword", use_lcm=False)
|
||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "pixel-art-xl.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SDXL_pixel-art.safetensors"
|
||||
ks = _ksampler(wf)["inputs"]
|
||||
assert ks["steps"] == 25 and ks["cfg"] == 7.0
|
||||
assert ks["sampler_name"] == "euler" and ks["scheduler"] == "normal"
|
||||
@@ -50,7 +50,7 @@ def test_edge_overrides_and_clamp():
|
||||
assert ks["steps"] == 12 and ks["cfg"] == 2.0
|
||||
px = next(
|
||||
n for n in wf.values()
|
||||
if n["class_type"] == "LoraLoader" and n["inputs"]["lora_name"] == "pixel-art-xl.safetensors"
|
||||
if n["class_type"] == "LoraLoader" and n["inputs"]["lora_name"] == "SDXL_pixel-art.safetensors"
|
||||
)
|
||||
assert px["inputs"]["strength_model"] == 2.0 # clamp a [0,2]
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler (y del sampler del FaceDetailer). Misma seed + mismo character/ref_face -> mismo retrato. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'anime_lineart_sd15.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_anime_lineart.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: weight
|
||||
|
||||
@@ -105,7 +105,7 @@ def comfyui_build_portrait_avatar_workflow(
|
||||
seed: semilla del KSampler (y del sampler del FaceDetailer). Misma seed +
|
||||
mismo character/ref_face -> mismo retrato. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'anime_lineart_sd15.safetensors'). None = sin LoRA. keyword-only.
|
||||
'SD15_anime_lineart.safetensors'). None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
weight: peso del IPAdapter-FaceID (solo si ref_face). 0.85 = parecido alto;
|
||||
|
||||
@@ -107,13 +107,13 @@ def test_edge_size_reflected_square():
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_portrait_avatar_workflow(
|
||||
"a dark sorceress",
|
||||
lora="anime_lineart_sd15.safetensors",
|
||||
lora="SD15_anime_lineart.safetensors",
|
||||
lora_strength=0.8,
|
||||
facedetailer=False,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "anime_lineart_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_anime_lineart.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||
|
||||
|
||||
@@ -135,9 +135,9 @@ def test_error_empty_character():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_portrait_avatar_workflow(
|
||||
"a young knight woman with red hair", lora="anime_lineart_sd15.safetensors", seed=7
|
||||
"a young knight woman with red hair", lora="SD15_anime_lineart.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_portrait_avatar_workflow(
|
||||
"a young knight woman with red hair", lora="anime_lineart_sd15.safetensors", seed=7
|
||||
"a young knight woman with red hair", lora="SD15_anime_lineart.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -32,7 +32,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.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
|
||||
|
||||
@@ -155,7 +155,7 @@ def comfyui_build_projectile_workflow(
|
||||
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.
|
||||
'SD15_detail_tweaker.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
|
||||
|
||||
@@ -119,11 +119,11 @@ def test_edge_style_reflected():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_projectile_workflow(
|
||||
"arrow", lora="detail_tweaker_sd15.safetensors", lora_strength=0.9
|
||||
"arrow", lora="SD15_detail_tweaker.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"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -148,9 +148,9 @@ def test_error_empty_projectile():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_projectile_workflow(
|
||||
"fireball", direction="right", glow=True, lora="detail_tweaker_sd15.safetensors", seed=7
|
||||
"fireball", direction="right", glow=True, lora="SD15_detail_tweaker.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_projectile_workflow(
|
||||
"fireball", direction="right", glow=True, lora="detail_tweaker_sd15.safetensors", seed=7
|
||||
"fireball", direction="right", glow=True, lora="SD15_detail_tweaker.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -28,7 +28,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Misma seed + mismo prop/style -> mismo objeto. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'isometric_game_assets_sd15.safetensors', 'stylized_props_xl.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_isometric_game_assets.safetensors', 'SDXL_stylized_props.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
|
||||
|
||||
@@ -146,7 +146,7 @@ def comfyui_build_prop_object_workflow(
|
||||
seed: semilla del KSampler. Misma seed + mismo prop/style -> mismo objeto.
|
||||
keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'isometric_game_assets_sd15.safetensors', 'stylized_props_xl.safetensors').
|
||||
'SD15_isometric_game_assets.safetensors', 'SDXL_stylized_props.safetensors').
|
||||
None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -102,12 +102,12 @@ def test_edge_world_object_not_inventory_icon():
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_prop_object_workflow(
|
||||
"ornate vase",
|
||||
lora="isometric_game_assets_sd15.safetensors",
|
||||
lora="SD15_isometric_game_assets.safetensors",
|
||||
lora_strength=0.9,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "isometric_game_assets_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_isometric_game_assets.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ def test_error_empty_prop():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_prop_object_workflow(
|
||||
"wooden barrel", lora="stylized_props_xl.safetensors", seed=7
|
||||
"wooden barrel", lora="SDXL_stylized_props.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_prop_object_workflow(
|
||||
"wooden barrel", lora="stylized_props_xl.safetensors", seed=7
|
||||
"wooden barrel", lora="SDXL_stylized_props.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -97,7 +97,7 @@ def test_edge_lora_injected_when_requested():
|
||||
wf_no = comfyui_build_rune_glyph_workflow("ward symbol")
|
||||
assert "LoraLoader" not in _classes(wf_no)
|
||||
wf_lora = comfyui_build_rune_glyph_workflow(
|
||||
"ward symbol", lora="arcane_style_sd15.safetensors", lora_strength=0.8
|
||||
"ward symbol", lora="SD15_arcane_style.safetensors", lora_strength=0.8
|
||||
)
|
||||
assert "LoraLoader" in _classes(wf_lora)
|
||||
ll = next(n for n in wf_lora.values() if n["class_type"] == "LoraLoader")
|
||||
|
||||
@@ -54,7 +54,7 @@ def test_edge_no_circular_vae():
|
||||
|
||||
def test_edge_material_lora_before_tile():
|
||||
wf = comfyui_build_seamless_tile_workflow(
|
||||
"stone", material_lora="detail_tweaker_sd15.safetensors", lora_strength=0.7
|
||||
"stone", material_lora="SD15_detail_tweaker.safetensors", lora_strength=0.7
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
|
||||
@@ -32,7 +32,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Fija el mismo seed en el par unlocked/locked del mismo talento para que coincidan. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'detail_tweaker_sd15.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.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
|
||||
|
||||
@@ -172,7 +172,7 @@ def comfyui_build_skill_tree_node_workflow(
|
||||
seed: semilla del KSampler. Fija el mismo seed en el par unlocked/locked del
|
||||
mismo talento para que coincidan. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'detail_tweaker_sd15.safetensors'). None = sin LoRA. keyword-only.
|
||||
'SD15_detail_tweaker.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
|
||||
|
||||
@@ -121,11 +121,11 @@ def test_edge_skill_reflected():
|
||||
def test_edge_lora_injected():
|
||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||
wf = comfyui_build_skill_tree_node_workflow(
|
||||
"whirlwind", lora="detail_tweaker_sd15.safetensors", lora_strength=0.8
|
||||
"whirlwind", lora="SD15_detail_tweaker.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "detail_tweaker_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.8)
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + misma scene -> misma ilustracion. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'concept_art_sd15.safetensors', 'cinematic_xl.safetensors'). None = sin LoRA. Encadena la identidad visual del juego. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_concept_art.safetensors', 'SDXL_cinematic.safetensors'). None = sin LoRA. Encadena la identidad visual del juego. keyword-only."
|
||||
- name: lora_strength
|
||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||
- name: negative
|
||||
|
||||
@@ -114,7 +114,7 @@ def comfyui_build_splash_art_workflow(
|
||||
seed: semilla del KSampler (y de la pasada hires). Misma seed + misma scene
|
||||
-> misma ilustracion. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'concept_art_sd15.safetensors', 'cinematic_xl.safetensors'). None = sin
|
||||
'SD15_concept_art.safetensors', 'SDXL_cinematic.safetensors'). None = sin
|
||||
LoRA. Encadena la identidad visual del juego. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -97,13 +97,13 @@ def test_edge_mood_in_prompt():
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_splash_art_workflow(
|
||||
"a knight raising a banner on a hill",
|
||||
lora="concept_art_sd15.safetensors",
|
||||
lora="SD15_concept_art.safetensors",
|
||||
lora_strength=0.9,
|
||||
hires=False,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "concept_art_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_concept_art.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
||||
ksampler = _by_class(wf, "KSampler")[0]
|
||||
|
||||
@@ -31,7 +31,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_dark_fantasy.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: preprocess
|
||||
|
||||
@@ -200,7 +200,7 @@ def comfyui_build_sprite_from_sketch_workflow(
|
||||
size: lado en px del sprite generado (EmptyLatentImage size x size). El preprocesador
|
||||
normaliza el boceto a esta resolucion. 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').
|
||||
lora: LoRA de estilo opcional en models/loras (ej. 'SD15_dark_fantasy.safetensors').
|
||||
None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only.
|
||||
preprocess: si True (default), inserta el preprocesador del control_type entre el
|
||||
|
||||
@@ -66,11 +66,11 @@ def test_edge_opaque_no_rembg():
|
||||
|
||||
def test_edge_char_lora():
|
||||
wf = comfyui_build_sprite_sheet_workflow(
|
||||
"a hero", char_lora="anime_style_box_sd15.safetensors", lora_strength=0.8
|
||||
"a hero", char_lora="SD15_anime_style_box.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "anime_style_box_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_anime_style_box.safetensors"
|
||||
|
||||
|
||||
def test_error_empty_subject():
|
||||
|
||||
@@ -28,7 +28,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.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
|
||||
@@ -69,7 +69,7 @@ wf = comfyui_build_status_effect_icon_workflow(
|
||||
# Barra de estados coherente: misma firma de estilo para cada efecto.
|
||||
# for fx in ["burning", "frozen", "shield", "regeneration", "stun", "speed boost"]:
|
||||
# wf = comfyui_build_status_effect_icon_workflow(fx, ui_style="game status icon, bold symbol, flat",
|
||||
# lora="detail_tweaker_sd15.safetensors", seed=42)
|
||||
# lora="SD15_detail_tweaker.safetensors", seed=42)
|
||||
# comfyui_submit_workflow(wf) # -> comfyui_wait_result -> comfyui_fetch_output_image
|
||||
# Atlas de estados: montar los PNG resultantes con comfyui_build_grid.
|
||||
```
|
||||
|
||||
@@ -141,7 +141,7 @@ def comfyui_build_status_effect_icon_workflow(
|
||||
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.
|
||||
'SD15_detail_tweaker.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).
|
||||
|
||||
@@ -95,11 +95,11 @@ def test_edge_effect_reflected():
|
||||
def test_edge_lora_injected():
|
||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||
wf = comfyui_build_status_effect_icon_workflow(
|
||||
"speed boost", lora="detail_tweaker_sd15.safetensors", lora_strength=0.8
|
||||
"speed boost", lora="SD15_detail_tweaker.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "detail_tweaker_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.8)
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Misma seed + misma structure/view/style -> mismo edificio. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo/isometrica opcional en models/loras (ej. 'isometric_game_assets_sd15.safetensors', 'stylized_buildings_xl.safetensors'). Para escenarios iso coherentes la LoRA iso fija el angulo 2:1. None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo/isometrica opcional en models/loras (ej. 'SD15_isometric_game_assets.safetensors', 'SDXL_stylized_buildings.safetensors'). Para escenarios iso coherentes la LoRA iso fija el angulo 2:1. 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
|
||||
@@ -106,7 +106,7 @@ cada una y monta los PNG con `comfyui_build_grid`.
|
||||
etéreas/translúcidas que quieras conservar, pon `transparent=False` y recorta aparte.
|
||||
- **`view` fija la perspectiva del mapa**: `isometric` (default) para mapas iso 2:1;
|
||||
`side`/`front` para plataformas; `top-down` para cenital; `3/4` para vista de ¾. Para
|
||||
iso estricto, añade la LoRA iso (`lora="isometric_game_assets_sd15.safetensors"`), que
|
||||
iso estricto, añade la LoRA iso (`lora="SD15_isometric_game_assets.safetensors"`), que
|
||||
fija mejor el ángulo 2:1 que solo el prompt.
|
||||
- **Coherencia del set = mismos parámetros**: si cambias `view`/`style`/`checkpoint`/`lora`/
|
||||
`seed` entre edificios, el escenario deja de combinar. Fija esos y varía solo `structure`.
|
||||
|
||||
@@ -149,7 +149,7 @@ def comfyui_build_structure_workflow(
|
||||
seed: semilla del KSampler. Misma seed + misma structure/view/style -> mismo
|
||||
edificio. keyword-only.
|
||||
lora: LoRA de estilo/isometrica opcional en models/loras (ej.
|
||||
'isometric_game_assets_sd15.safetensors', 'stylized_buildings_xl.safetensors').
|
||||
'SD15_isometric_game_assets.safetensors', 'SDXL_stylized_buildings.safetensors').
|
||||
Para escenarios isometricos coherentes, la LoRA iso ayuda a fijar el angulo
|
||||
2:1. None = sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
|
||||
@@ -123,12 +123,12 @@ def test_edge_building_not_small_prop():
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_structure_workflow(
|
||||
"wizard tower",
|
||||
lora="isometric_game_assets_sd15.safetensors",
|
||||
lora="SD15_isometric_game_assets.safetensors",
|
||||
lora_strength=0.9,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "isometric_game_assets_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_isometric_game_assets.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -148,9 +148,9 @@ def test_error_empty_structure():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_structure_workflow(
|
||||
"wizard tower", lora="stylized_buildings_xl.safetensors", seed=7
|
||||
"wizard tower", lora="SDXL_stylized_buildings.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_structure_workflow(
|
||||
"wizard tower", lora="stylized_buildings_xl.safetensors", seed=7
|
||||
"wizard tower", lora="SDXL_stylized_buildings.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -121,11 +121,11 @@ def test_edge_negative_allows_text():
|
||||
def test_edge_lora_injected():
|
||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||
wf = comfyui_build_title_lettering_workflow(
|
||||
"EMPIRE", lora="logo_style_sd15.safetensors", lora_strength=0.7
|
||||
"EMPIRE", lora="SD15_logo_style.safetensors", lora_strength=0.7
|
||||
)
|
||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "logo_style_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_logo_style.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.7)
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Misma seed + misma subject/style -> misma figura; variar solo `direction` da las vistas coherentes de movimiento. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo/top-down opcional en models/loras (ej. 'topdown_rpg_sd15.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo/top-down opcional en models/loras (ej. 'SD15_topdown_rpg.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
|
||||
|
||||
@@ -154,7 +154,7 @@ def comfyui_build_topdown_sprite_workflow(
|
||||
figura; variar solo `direction` da las vistas coherentes de movimiento.
|
||||
keyword-only.
|
||||
lora: LoRA de estilo/top-down opcional en models/loras (ej.
|
||||
'topdown_rpg_sd15.safetensors'). None = sin LoRA. keyword-only.
|
||||
'SD15_topdown_rpg.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
|
||||
|
||||
@@ -111,11 +111,11 @@ def test_edge_style_in_prompt():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_topdown_sprite_workflow(
|
||||
"a knight character", lora="topdown_rpg_sd15.safetensors", lora_strength=0.9
|
||||
"a knight character", lora="SD15_topdown_rpg.safetensors", lora_strength=0.9
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "topdown_rpg_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_topdown_rpg.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -129,9 +129,9 @@ def test_error_empty_subject():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_topdown_sprite_workflow(
|
||||
"a knight character", direction="east", lora="topdown_rpg_sd15.safetensors", seed=5
|
||||
"a knight character", direction="east", lora="SD15_topdown_rpg.safetensors", seed=5
|
||||
)
|
||||
b = comfyui_build_topdown_sprite_workflow(
|
||||
"a knight character", direction="east", lora="topdown_rpg_sd15.safetensors", seed=5
|
||||
"a knight character", direction="east", lora="SD15_topdown_rpg.safetensors", seed=5
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Misma seed + mismo hazard/view/style -> misma trampa. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'pixel_art_sd15.safetensors', 'stylized_game_assets_xl.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_pixel_art.safetensors', 'SDXL_stylized_game_assets.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
|
||||
|
||||
@@ -151,7 +151,7 @@ def comfyui_build_trap_hazard_workflow(
|
||||
seed: semilla del KSampler. Misma seed + mismo hazard/view/style -> misma trampa.
|
||||
keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'pixel_art_sd15.safetensors', 'stylized_game_assets_xl.safetensors'). None =
|
||||
'SD15_pixel_art.safetensors', 'SDXL_stylized_game_assets.safetensors'). None =
|
||||
sin LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -118,11 +118,11 @@ def test_edge_negative_rejects_living_character():
|
||||
|
||||
def test_edge_lora_injected():
|
||||
wf = comfyui_build_trap_hazard_workflow(
|
||||
"bear trap", lora="pixel_art_sd15.safetensors", lora_strength=0.8
|
||||
"bear trap", lora="SD15_pixel_art.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "pixel_art_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_pixel_art.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ params:
|
||||
- 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."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_detail_tweaker.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
|
||||
@@ -69,7 +69,7 @@ wf = comfyui_build_ui_hud_workflow(
|
||||
# HUD coherente: misma firma de estilo para cada pieza de la interfaz.
|
||||
# for el in ["wooden button", "ornate frame", "mana orb", "menu cursor"]:
|
||||
# wf = comfyui_build_ui_hud_workflow(el, ui_style="fantasy game UI",
|
||||
# lora="detail_tweaker_sd15.safetensors", seed=42)
|
||||
# lora="SD15_detail_tweaker.safetensors", seed=42)
|
||||
# comfyui_submit_workflow(wf) # -> comfyui_wait_result -> comfyui_fetch_output_image
|
||||
# Atlas del HUD: montar los PNG resultantes con comfyui_build_grid.
|
||||
```
|
||||
|
||||
@@ -129,7 +129,7 @@ def comfyui_build_ui_hud_workflow(
|
||||
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.
|
||||
'SD15_detail_tweaker.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).
|
||||
|
||||
@@ -74,11 +74,11 @@ def test_edge_ui_style_in_prompt():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_ui_hud_workflow(
|
||||
"magic icon", lora="detail_tweaker_sd15.safetensors", lora_strength=0.9
|
||||
"magic icon", lora="SD15_detail_tweaker.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"]["lora_name"] == "SD15_detail_tweaker.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -91,6 +91,6 @@ def test_error_empty_element():
|
||||
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_ui_hud_workflow("menu cursor", lora="detail_tweaker_sd15.safetensors", seed=7)
|
||||
b = comfyui_build_ui_hud_workflow("menu cursor", lora="detail_tweaker_sd15.safetensors", seed=7)
|
||||
a = comfyui_build_ui_hud_workflow("menu cursor", lora="SD15_detail_tweaker.safetensors", seed=7)
|
||||
b = comfyui_build_ui_hud_workflow("menu cursor", lora="SD15_detail_tweaker.safetensors", seed=7)
|
||||
assert a == b
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler. Misma seed + mismo vehicle/view/style -> mismo vehiculo. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'vehicle_concept_sd15.safetensors', 'mecha_xl.safetensors'). None = sin LoRA. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_vehicle_concept.safetensors', 'SDXL_mecha.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
|
||||
|
||||
@@ -153,7 +153,7 @@ def comfyui_build_vehicle_mount_workflow(
|
||||
seed: semilla del KSampler. Misma seed + mismo vehicle/view/style -> mismo
|
||||
vehiculo. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej.
|
||||
'vehicle_concept_sd15.safetensors', 'mecha_xl.safetensors'). None = sin
|
||||
'SD15_vehicle_concept.safetensors', 'SDXL_mecha.safetensors'). None = sin
|
||||
LoRA. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -98,11 +98,11 @@ def test_edge_style_in_prompt():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_vehicle_mount_workflow(
|
||||
"mecha walker", lora="mecha_xl.safetensors", lora_strength=0.9
|
||||
"mecha walker", lora="SDXL_mecha.safetensors", lora_strength=0.9
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "mecha_xl.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SDXL_mecha.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
|
||||
|
||||
@@ -116,9 +116,9 @@ def test_error_empty_vehicle():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_vehicle_mount_workflow(
|
||||
"griffon mount", view="iso", lora="vehicle_concept_sd15.safetensors", seed=7
|
||||
"griffon mount", view="iso", lora="SD15_vehicle_concept.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_vehicle_mount_workflow(
|
||||
"griffon mount", view="iso", lora="vehicle_concept_sd15.safetensors", seed=7
|
||||
"griffon mount", view="iso", lora="SD15_vehicle_concept.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -47,7 +47,7 @@ def test_edge_open_loop():
|
||||
|
||||
def test_edge_lora_fx():
|
||||
wf = comfyui_build_vfx_spritesheet_workflow(
|
||||
"explosion", lora="detail_tweaker_sd15.safetensors", lora_strength=1.0
|
||||
"explosion", lora="SD15_detail_tweaker.safetensors", lora_strength=1.0
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
|
||||
@@ -119,11 +119,11 @@ def test_edge_negative_isolates_layer():
|
||||
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_weather_overlay_workflow(
|
||||
"falling snow", lora="vfx_sd15.safetensors", lora_strength=0.8
|
||||
"falling snow", lora="SD15_vfx.safetensors", lora_strength=0.8
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "vfx_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_vfx.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||
|
||||
|
||||
@@ -137,9 +137,9 @@ def test_error_empty_weather():
|
||||
|
||||
def test_determinism():
|
||||
a = comfyui_build_weather_overlay_workflow(
|
||||
"heavy rain", on_black=True, lora="vfx_sd15.safetensors", seed=7
|
||||
"heavy rain", on_black=True, lora="SD15_vfx.safetensors", seed=7
|
||||
)
|
||||
b = comfyui_build_weather_overlay_workflow(
|
||||
"heavy rain", on_black=True, lora="vfx_sd15.safetensors", seed=7
|
||||
"heavy rain", on_black=True, lora="SD15_vfx.safetensors", seed=7
|
||||
)
|
||||
assert a == b
|
||||
|
||||
@@ -30,7 +30,7 @@ params:
|
||||
- name: seed
|
||||
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + misma region -> mismo mapa. keyword-only."
|
||||
- name: lora
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'cartography_sd15.safetensors', 'old_map_xl.safetensors'). None = sin LoRA. Encadena la identidad visual del mapa del juego. keyword-only."
|
||||
desc: "LoRA de estilo opcional en models/loras (ej. 'SD15_cartography.safetensors', 'SDXL_old_map.safetensors'). None = sin LoRA. Encadena la identidad visual del mapa del juego. keyword-only."
|
||||
- name: lora_strength
|
||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||
- name: negative
|
||||
|
||||
@@ -116,7 +116,7 @@ def comfyui_build_world_map_workflow(
|
||||
seed: semilla del KSampler (y de la pasada hires). Misma seed + misma region
|
||||
-> mismo mapa. keyword-only.
|
||||
lora: LoRA de estilo opcional en models/loras (ej. 'cartography_sd15.safe-
|
||||
tensors', 'old_map_xl.safetensors'). None = sin LoRA. Encadena la
|
||||
tensors', 'SDXL_old_map.safetensors'). None = sin LoRA. Encadena la
|
||||
identidad visual del mapa del juego. keyword-only.
|
||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||
keyword-only.
|
||||
|
||||
@@ -101,13 +101,13 @@ def test_edge_map_style_in_prompt():
|
||||
def test_edge_lora_reflected():
|
||||
wf = comfyui_build_world_map_workflow(
|
||||
"an archipelago of volcanic islands",
|
||||
lora="cartography_sd15.safetensors",
|
||||
lora="SD15_cartography.safetensors",
|
||||
lora_strength=0.9,
|
||||
hires=False,
|
||||
)
|
||||
loras = _by_class(wf, "LoraLoader")
|
||||
assert len(loras) == 1
|
||||
assert loras[0]["inputs"]["lora_name"] == "cartography_sd15.safetensors"
|
||||
assert loras[0]["inputs"]["lora_name"] == "SD15_cartography.safetensors"
|
||||
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
||||
ksampler = _by_class(wf, "KSampler")[0]
|
||||
|
||||
@@ -48,8 +48,8 @@ base = comfyui_build_txt2img_workflow("dreamshaper_8.safetensors", "a hero, 3d r
|
||||
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},
|
||||
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||
],
|
||||
facedetailer={"denoise": 0.45},
|
||||
# controlnet=..., ipadapter=..., hires=... -> None = desactivadas
|
||||
|
||||
@@ -195,8 +195,8 @@ if __name__ == "__main__":
|
||||
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},
|
||||
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||
],
|
||||
facedetailer={"denoise": 0.45},
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ params:
|
||||
desc: "Identificador del estilo: 'gameboy', 'ghibli' o 'pixel-art-retro'. Insensible a mayusculas y a '_' vs '-'. Si es None o cadena vacia devuelve el catalogo {names, count} en vez de una receta (discovery)."
|
||||
output: "Si name es None/'': dict {names: list[str], count: int} con el catalogo. Si name es valido: copia profunda de la receta del estilo con campos {name, subject_prefix, subject_suffix, style, negative, checkpoint, lora, lora_strength, size, transparent, post, notes}. Es una COPIA — mutarla no afecta al registro interno."
|
||||
tested: true
|
||||
tests: ["golden: los 3 presets (gameboy/ghibli/pixel-art-retro) devuelven recetas con todos los campos requeridos, checkpoint .safetensors, size>0", "golden gameboy: lora None + post pixelize paleta game-boy 4 colores", "golden pixel-art-retro: lora pixel-art-xl SDXL + checkpoint juggernaut + size>=768 + post pixelize", "golden ghibli: degrada a watercolor_style_sd15 + sin post pixelize", "edge name None/'' -> catalogo de 3 nombres", "edge insensible a mayusculas y '_'/'-'", "edge devuelve copia profunda (mutar no afecta), error name desconocido -> ValueError listando disponibles"]
|
||||
tests: ["golden: los 3 presets (gameboy/ghibli/pixel-art-retro) devuelven recetas con todos los campos requeridos, checkpoint .safetensors, size>0", "golden gameboy: lora None + post pixelize paleta game-boy 4 colores", "golden pixel-art-retro: lora SDXL_pixel-art SDXL + checkpoint juggernaut + size>=768 + post pixelize", "golden ghibli: degrada a SD15_watercolor_style + sin post pixelize", "edge name None/'' -> catalogo de 3 nombres", "edge insensible a mayusculas y '_'/'-'", "edge devuelve copia profunda (mutar no afecta), error name desconocido -> ValueError listando disponibles"]
|
||||
test_file_path: "python/functions/ml/comfyui_get_gamedev_style_preset_test.py"
|
||||
file_path: "python/functions/ml/comfyui_get_gamedev_style_preset.py"
|
||||
---
|
||||
@@ -64,11 +64,11 @@ para descubrir los estilos disponibles.
|
||||
`comfyui_submit_workflow`/`comfyui_wait_result`/`comfyui_fetch_output_image` +
|
||||
`comfyui_pixelize_image`.
|
||||
- **El checkpoint y el LoRA deben casar de base**: `pixel-art-retro` usa el LoRA SDXL
|
||||
`pixel-art-xl` -> exige `checkpoint` SDXL (`juggernaut_xl_v11`) y `size` 768. Aplicar un
|
||||
`SDXL_pixel-art` -> exige `checkpoint` SDXL (`juggernaut_xl_v11`) y `size` 768. Aplicar un
|
||||
LoRA SDXL sobre un checkpoint SD1.5 da basura. Si anades un estilo con LoRA nuevo,
|
||||
descargalo a `models/loras` y verifica su base antes.
|
||||
- **ghibli no usa un LoRA Ghibli dedicado**: no hay ninguno instalado y no se descargo
|
||||
ninguno gated/de pago. Degrada a `watercolor_style_sd15` (gratis, ya instalado) +
|
||||
ninguno gated/de pago. Degrada a `SD15_watercolor_style` (gratis, ya instalado) +
|
||||
prompt Ghibli para el look pintado/acuarela. Un LoRA Ghibli especifico de Civitai
|
||||
mejoraria el parecido facial — pendiente humano.
|
||||
- **gameboy se resuelve por POST, no por LoRA**: sin LoRA; el look DMG de 4 tonos verde lo
|
||||
@@ -76,8 +76,8 @@ para descubrir los estilos disponibles.
|
||||
aplicar el post (`preset["post"]["pixelize"]`) o solo vera un sprite monocromo-ish sin
|
||||
la paleta sellada.
|
||||
- **Modelos verificados en el servidor** (8GB lowvram, modelos en `/mnt/2tb`): si cambias
|
||||
de PC valida que `dreamshaper_8`, `juggernaut_xl_v11`, `pixel-art-xl` y
|
||||
`watercolor_style_sd15` existan (`GET /object_info/CheckpointLoaderSimple` y `/LoraLoader`).
|
||||
de PC valida que `dreamshaper_8`, `juggernaut_xl_v11`, `SDXL_pixel-art` y
|
||||
`SD15_watercolor_style` existan (`GET /object_info/CheckpointLoaderSimple` y `/LoraLoader`).
|
||||
|
||||
## Capability growth log
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ import copy
|
||||
|
||||
# Modelos verificados presentes en el servidor (8GB lowvram, modelos en /mnt/2tb):
|
||||
# checkpoints: dreamshaper_8 (SD1.5), juggernaut_xl_v11 (SDXL)
|
||||
# loras: pixel-art-xl (SDXL), watercolor_style_sd15 (SD1.5), ...
|
||||
# loras: SDXL_pixel-art (SDXL), SD15_watercolor_style (SD1.5), ...
|
||||
# Si se anade un estilo con un LoRA nuevo, descargar antes a models/loras y verificar
|
||||
# que el `checkpoint` casa con su base (un LoRA SDXL exige checkpoint SDXL).
|
||||
_PRESETS: dict[str, dict] = {
|
||||
@@ -82,7 +82,7 @@ _PRESETS: dict[str, dict] = {
|
||||
},
|
||||
# Studio Ghibli: anime pintado a mano, colores suaves, fondos acuarela. No hay un LoRA
|
||||
# Ghibli dedicado instalado (no se descargo ninguno gated/de pago); el look pintado se
|
||||
# logra con watercolor_style_sd15 (LoRA gratis ya instalado) a fuerza media + prompt
|
||||
# logra con SD15_watercolor_style (LoRA gratis ya instalado) a fuerza media + prompt
|
||||
# Ghibli. Sin post-proceso (es ilustracion pintada, no pixelart).
|
||||
"ghibli": {
|
||||
"name": "ghibli",
|
||||
@@ -91,20 +91,20 @@ _PRESETS: dict[str, dict] = {
|
||||
"style": "Studio Ghibli style, hand-painted anime, soft colors, watercolor background, whimsical, gentle, detailed illustration",
|
||||
"negative": "photo, photorealistic, 3d render, harsh shadows, pixel art, lowres, deformed, text, watermark, signature",
|
||||
"checkpoint": "dreamshaper_8.safetensors",
|
||||
"lora": "watercolor_style_sd15.safetensors",
|
||||
"lora": "SD15_watercolor_style.safetensors",
|
||||
"lora_strength": 0.7,
|
||||
"size": 512,
|
||||
"transparent": False,
|
||||
"post": {},
|
||||
"notes": (
|
||||
"No hay LoRA Ghibli dedicado instalado y no se descargo ninguno gated/de pago "
|
||||
"(error-path: degradar a LoRA gratis + prompt). watercolor_style_sd15 (gratis, ya "
|
||||
"(error-path: degradar a LoRA gratis + prompt). SD15_watercolor_style (gratis, ya "
|
||||
"instalado) a strength 0.7 + prompt Ghibli da el look pintado/acuarela. Un LoRA "
|
||||
"Ghibli especifico de Civitai mejoraria el parecido facial — pendiente humano si "
|
||||
"se quiere. transparent=False para conservar el fondo acuarela."
|
||||
),
|
||||
},
|
||||
# Pixel-art retro 16-bit (SNES/Genesis): reutiliza el LoRA pixel-art-xl ya instalado
|
||||
# Pixel-art retro 16-bit (SNES/Genesis): reutiliza el LoRA SDXL_pixel-art ya instalado
|
||||
# (es SDXL -> exige checkpoint SDXL juggernaut_xl_v11 y resolucion mayor). El post
|
||||
# pixelize a 16 colores sella los pixeles duros (el LoRA da el estilo, el post el grid).
|
||||
"pixel-art-retro": {
|
||||
@@ -114,7 +114,7 @@ _PRESETS: dict[str, dict] = {
|
||||
"style": "16-bit pixel art, SNES JRPG sprite, retro game, limited palette, clean outline, flat colors",
|
||||
"negative": "blurry, smooth, photorealistic, 3d render, realistic, antialiasing, soft, gradient, noise",
|
||||
"checkpoint": "juggernaut_xl_v11.safetensors",
|
||||
"lora": "pixel-art-xl.safetensors",
|
||||
"lora": "SDXL_pixel-art.safetensors",
|
||||
"lora_strength": 1.0,
|
||||
"size": 768,
|
||||
"transparent": False,
|
||||
@@ -128,8 +128,8 @@ _PRESETS: dict[str, dict] = {
|
||||
}
|
||||
},
|
||||
"notes": (
|
||||
"Reutiliza pixel-art-xl.safetensors (SDXL, ya instalado) -> requiere checkpoint "
|
||||
"SDXL juggernaut_xl_v11 y size 768 (a 512 SDXL+pixel-art-xl pierde calidad). El "
|
||||
"Reutiliza SDXL_pixel-art.safetensors (SDXL, ya instalado) -> requiere checkpoint "
|
||||
"SDXL juggernaut_xl_v11 y size 768 (a 512 SDXL+SDXL_pixel-art pierde calidad). El "
|
||||
"post pixelize a 16 colores (paleta auto MEDIANCUT) da el grid duro 16-bit. OOM en "
|
||||
"8GB -> bajar size a 512 (NO matar procesos). El LoRA da el estilo; el post el grid."
|
||||
),
|
||||
@@ -176,7 +176,7 @@ _PRESETS: dict[str, dict] = {
|
||||
"transparent": True,
|
||||
"post": {},
|
||||
"notes": (
|
||||
"Sin LoRA a propósito: 3d_render_redmond_sd15 (instalado) empuja a render "
|
||||
"Sin LoRA a propósito: SD15_3d_render_redmond (instalado) empuja a render "
|
||||
"fotorrealista, lo OPUESTO a low-poly. El look faceteado/flat lo da el prompt "
|
||||
"(low poly, faceted, flat shading, PS1) sobre dreamshaper_8 (SD1.5). Sin post: el "
|
||||
"flat shading es limpio de por sí, no necesita pixelize. transparent=True porque un "
|
||||
@@ -185,7 +185,7 @@ _PRESETS: dict[str, dict] = {
|
||||
},
|
||||
# Cartoon cel-shaded: dibujos animados / anime con sombreado plano por celdas, líneas
|
||||
# negras gruesas, colores saturados y planos (look toon/Borderlands/Zelda Wind Waker).
|
||||
# Usa anime_style_box_sd15 (LoRA gratis ya instalado) a fuerza media + prompt cel-shaded.
|
||||
# Usa SD15_anime_style_box (LoRA gratis ya instalado) a fuerza media + prompt cel-shaded.
|
||||
# Sin post (es ilustración vectorial limpia, no pixelart).
|
||||
"cartoon-cel-shaded": {
|
||||
"name": "cartoon-cel-shaded",
|
||||
@@ -194,13 +194,13 @@ _PRESETS: dict[str, dict] = {
|
||||
"style": "cartoon cel-shaded art, bold black outlines, flat color fills, hard cel shadows, vibrant saturated colors, clean vector look, anime toon shading, comic style",
|
||||
"negative": "photorealistic, soft shading, gradient, realistic texture, painterly, blurry, noisy, pixel art, lowres, grainy, deformed, text, watermark, signature",
|
||||
"checkpoint": "dreamshaper_8.safetensors",
|
||||
"lora": "anime_style_box_sd15.safetensors",
|
||||
"lora": "SD15_anime_style_box.safetensors",
|
||||
"lora_strength": 0.7,
|
||||
"size": 512,
|
||||
"transparent": True,
|
||||
"post": {},
|
||||
"notes": (
|
||||
"anime_style_box_sd15.safetensors (gratis, ya instalado en /mnt/2tb) a strength 0.7 "
|
||||
"SD15_anime_style_box.safetensors (gratis, ya instalado en /mnt/2tb) a strength 0.7 "
|
||||
"empuja el toon/anime; el prompt sella el cel-shading (outlines negros gruesos, "
|
||||
"sombras duras por celdas, colores planos saturados). SD1.5 (dreamshaper_8). Sin "
|
||||
"post: el look vectorial limpio no necesita pixelize. transparent=True para recortar "
|
||||
|
||||
@@ -48,8 +48,8 @@ def test_golden_gameboy_recipe():
|
||||
|
||||
def test_golden_pixel_retro_uses_sdxl_lora():
|
||||
r = comfyui_get_gamedev_style_preset("pixel-art-retro")
|
||||
# Reutiliza pixel-art-xl (SDXL) -> checkpoint SDXL + size mayor + pixelize.
|
||||
assert r["lora"] == "pixel-art-xl.safetensors"
|
||||
# Reutiliza SDXL_pixel-art (SDXL) -> checkpoint SDXL + size mayor + pixelize.
|
||||
assert r["lora"] == "SDXL_pixel-art.safetensors"
|
||||
assert r["checkpoint"] == "juggernaut_xl_v11.safetensors"
|
||||
assert r["size"] >= 768
|
||||
assert "pixelize" in r["post"]
|
||||
@@ -58,7 +58,7 @@ def test_golden_pixel_retro_uses_sdxl_lora():
|
||||
def test_golden_ghibli_degrades_to_watercolor_lora():
|
||||
r = comfyui_get_gamedev_style_preset("ghibli")
|
||||
# Sin LoRA Ghibli dedicado -> watercolor instalado + prompt; sin post pixelize.
|
||||
assert r["lora"] == "watercolor_style_sd15.safetensors"
|
||||
assert r["lora"] == "SD15_watercolor_style.safetensors"
|
||||
assert r["post"] == {}
|
||||
assert "ghibli" in r["style"].lower()
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ from ml.comfyui_inject_multi_lora import comfyui_inject_multi_lora
|
||||
from ml.comfyui_inject_ipadapter import comfyui_inject_ipadapter
|
||||
|
||||
base = comfyui_build_txt2img_workflow("dreamshaper_8.safetensors", "portrait of a knight")
|
||||
wf = comfyui_inject_multi_lora(base, [{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5}])
|
||||
wf = comfyui_inject_multi_lora(base, [{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5}])
|
||||
wf = comfyui_inject_ipadapter(wf, "hero_face.png", mode="faceid", weight=0.9)
|
||||
# KSampler.model viene de IPAdapterFaceID(model=ultimo LoraLoader, image=hero_face)
|
||||
```
|
||||
|
||||
@@ -36,8 +36,8 @@ from ml.comfyui_inject_multi_lora import comfyui_inject_multi_lora
|
||||
|
||||
base = comfyui_build_txt2img_workflow("dreamshaper_8.safetensors", "a robot, 3D Render Style")
|
||||
wf = comfyui_inject_multi_lora(base, [
|
||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
||||
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
||||
])
|
||||
# Cadena: checkpoint -> 3d_render (0.9) -> detail_tweaker (0.5/0.5) -> KSampler/CLIPTextEncode
|
||||
```
|
||||
|
||||
@@ -79,8 +79,8 @@ if __name__ == "__main__":
|
||||
wf = comfyui_inject_multi_lora(
|
||||
base,
|
||||
[
|
||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
||||
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
||||
],
|
||||
)
|
||||
print(json.dumps(wf, indent=2))
|
||||
|
||||
@@ -43,7 +43,7 @@ import sys, os
|
||||
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
|
||||
from ml.comfyui_pixelize_image import comfyui_pixelize_image
|
||||
|
||||
# Crudo SDXL+pixel-art-xl 1024x1024 -> pixelart 16 colores, grid de 128
|
||||
# Crudo SDXL+SDXL_pixel-art 1024x1024 -> pixelart 16 colores, grid de 128
|
||||
res = comfyui_pixelize_image(
|
||||
os.path.expanduser("~/ComfyUI/output/pixelart_00001_.png"),
|
||||
"/tmp/hero_pixel.png",
|
||||
@@ -58,7 +58,7 @@ comfyui_pixelize_image("/tmp/hero_pixel.png", "/tmp/hero_gb.png",
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Fase 2 del pipeline pixelart: tras generar el crudo (SDXL + LoRA `pixel-art-xl`),
|
||||
Fase 2 del pipeline pixelart: tras generar el crudo (SDXL + LoRA `SDXL_pixel-art`),
|
||||
para colapsar el grid borroso a pixeles duros y limitar la paleta. Tambien sirve
|
||||
para "pixelizar" cualquier imagen (sprite, render, foto) a estetica retro sin
|
||||
tocar la GPU. Para llevar el resultado a Godot con filtro Nearest:
|
||||
|
||||
@@ -5,7 +5,7 @@ verdad: downscale nearest-neighbor por factor (colapsa cada bloque borroso a un
|
||||
pixel duro) -> cuantizacion a N colores o a una paleta fija (NES / Game Boy /
|
||||
PICO-8) -> opcional re-upscale nearest conservando los pixeles duros.
|
||||
|
||||
Es la Fase 2 del pipeline pixelart (la Fase 1, generar con SDXL + pixel-art-xl
|
||||
Es la Fase 2 del pipeline pixelart (la Fase 1, generar con SDXL + SDXL_pixel-art
|
||||
LoRA, vive en otra funcion). Determinista y CPU-only: el nucleo `_pixelize_pil`
|
||||
es puro (PIL), no toca la GPU ni la red. La funcion publica es impura solo por la
|
||||
lectura/escritura de disco (mismo patron que comfyui_build_grid).
|
||||
|
||||
@@ -40,8 +40,8 @@ def test_solo_loras_encadena():
|
||||
out = comfyui_compose_capabilities(
|
||||
base,
|
||||
loras=[
|
||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5},
|
||||
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||
],
|
||||
)
|
||||
assert_api_format(out)
|
||||
@@ -54,7 +54,7 @@ def test_solo_loras_encadena():
|
||||
def test_loras_mas_facedetailer():
|
||||
out = comfyui_compose_capabilities(
|
||||
_base(),
|
||||
loras=[{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5}],
|
||||
loras=[{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5}],
|
||||
facedetailer={"denoise": 0.45},
|
||||
)
|
||||
assert_api_format(out)
|
||||
|
||||
Reference in New Issue
Block a user