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:
@@ -299,8 +299,8 @@ res = comfyui_generate_mixed_oneshot(
|
|||||||
checkpoint="dreamshaper_8.safetensors",
|
checkpoint="dreamshaper_8.safetensors",
|
||||||
capabilities={
|
capabilities={
|
||||||
"loras": [
|
"loras": [
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
||||||
],
|
],
|
||||||
"facedetailer": {"denoise": 0.45},
|
"facedetailer": {"denoise": 0.45},
|
||||||
# "ipadapter": {"ref_image": "face.png", "mode": "faceid"}, # se activa con solo añadirla
|
# "ipadapter": {"ref_image": "face.png", "mode": "faceid"}, # se activa con solo añadirla
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ VFX (ver `reports/0143`).
|
|||||||
|
|
||||||
| ID | Firma corta | Qué hace |
|
| ID | Firma corta | Qué hace |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `comfyui_build_pixelart_workflow_py_ml` | `(positive, negative=…, *, ckpt_name="juggernaut_xl_v11…", pixel_lora="pixel-art-xl…", use_lcm=True, …) -> dict` | Fase 1 pixel-art: SDXL + LoRA pixel-art-xl (+ LCM 8 steps). El pixel-perfect es post (`comfyui_pixelize_image`). |
|
| `comfyui_build_pixelart_workflow_py_ml` | `(positive, negative=…, *, ckpt_name="juggernaut_xl_v11…", pixel_lora="SDXL_pixel-art…", use_lcm=True, …) -> dict` | Fase 1 pixel-art: SDXL + LoRA SDXL_pixel-art (+ LCM 8 steps). El pixel-perfect es post (`comfyui_pixelize_image`). |
|
||||||
| `comfyui_build_seamless_tile_workflow_py_ml` | `(positive, negative="", *, tiling="enable", copy_model="Make a copy", circular_vae=True, material_lora=None, …) -> dict` | Textura tileable: `SeamlessTile` (Conv2d circular) + `CircularVAEDecode`. Coste VRAM ≈0. |
|
| `comfyui_build_seamless_tile_workflow_py_ml` | `(positive, negative="", *, tiling="enable", copy_model="Make a copy", circular_vae=True, material_lora=None, …) -> dict` | Textura tileable: `SeamlessTile` (Conv2d circular) + `CircularVAEDecode`. Coste VRAM ≈0. |
|
||||||
| `comfyui_build_isometric_workflow_py_ml` | `(positive, negative=…, *, iso_lora="isometric_game_assets_sd15…", grid_image=None, …) -> dict` | Asset iso 2:1: LoRA iso + ControlNet grid opcional. |
|
| `comfyui_build_isometric_workflow_py_ml` | `(positive, negative=…, *, iso_lora="SD15_isometric_game_assets…", grid_image=None, …) -> dict` | Asset iso 2:1: LoRA iso + ControlNet grid opcional. |
|
||||||
| `comfyui_build_sprite_sheet_workflow_py_ml` | `(subject, *, ref_image=None, pose_skeleton=None, char_lora=None, transparent=True, …) -> dict` | UN sprite de personaje: IPAdapter-FaceID + LoRA + ControlNet OpenPose (Advanced, end<1) + Rembg. Varias poses → sheet. SD1.5. |
|
| `comfyui_build_sprite_sheet_workflow_py_ml` | `(subject, *, ref_image=None, pose_skeleton=None, char_lora=None, transparent=True, …) -> dict` | UN sprite de personaje: IPAdapter-FaceID + LoRA + ControlNet OpenPose (Advanced, end<1) + Rembg. Varias poses → sheet. SD1.5. |
|
||||||
| `comfyui_build_vfx_spritesheet_workflow_py_ml` | `(prompt, *, motion_model="mm_sd_v15_v2.ckpt", num_frames=16, closed_loop=True, lora=None, …) -> dict` | N frames AnimateDiff loop sobre negro (insumo de luma→alpha). 8GB: 16f@512² revienta, usar ≤8f@512² o bajar resolución. |
|
| `comfyui_build_vfx_spritesheet_workflow_py_ml` | `(prompt, *, motion_model="mm_sd_v15_v2.ckpt", num_frames=16, closed_loop=True, lora=None, …) -> dict` | N frames AnimateDiff loop sobre negro (insumo de luma→alpha). 8GB: 16f@512² revienta, usar ≤8f@512² o bajar resolución. |
|
||||||
| `comfyui_build_item_icon_workflow_py_ml` | `(item, *, style="game icon, clean, centered", checkpoint="dreamshaper_8…", size=512, transparent=True, lora=None, …) -> dict` | UN icono de item de inventario (espada/poción/anillo/libro/escudo): txt2img cuadrado + prompt scaffold de icono + LoRA estilo opcional + Rembg (alpha). Set coherente = mismo style/checkpoint/lora por item. SD1.5. |
|
| `comfyui_build_item_icon_workflow_py_ml` | `(item, *, style="game icon, clean, centered", checkpoint="dreamshaper_8…", size=512, transparent=True, lora=None, …) -> dict` | UN icono de item de inventario (espada/poción/anillo/libro/escudo): txt2img cuadrado + prompt scaffold de icono + LoRA estilo opcional + Rembg (alpha). Set coherente = mismo style/checkpoint/lora por item. SD1.5. |
|
||||||
@@ -150,7 +150,7 @@ firmas. Extensible: añadir un estilo = una entrada en `_PRESETS`.
|
|||||||
|
|
||||||
| ID | Firma corta | Qué hace |
|
| ID | Firma corta | Qué hace |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `comfyui_get_gamedev_style_preset_py_ml` | `(name=None) -> dict` | Devuelve la receta de un STYLE PRESET curado o el catálogo si `name=None`. Receta = `{subject_prefix, subject_suffix, style, negative, checkpoint, lora, lora_strength, size, transparent, post, notes}`. Pura, copias profundas. **6 estilos**: **gameboy** (sin LoRA → prompt + post `pixelize` paleta `game-boy` 4 tonos verde), **ghibli** (degrada a `watercolor_style_sd15` gratis instalado + prompt; no hay LoRA Ghibli dedicado ni se descargó nada gated), **pixel-art-retro** (reutiliza `pixel-art-xl` SDXL ya instalado → checkpoint `juggernaut_xl_v11` + size 768 + post `pixelize` 16 colores), **cyberpunk-neon** (prompt puro SD1.5, glow magenta/cyan, sin post), **low-poly-flat** (prompt puro SD1.5, facetas/flat shading PS1, sin post, transparent), **cartoon-cel-shaded** (LoRA `anime_style_box_sd15` 0.7 + prompt cel-shaded, sin post, transparent). Extensible: añadir un estilo = una entrada en `_PRESETS`. |
|
| `comfyui_get_gamedev_style_preset_py_ml` | `(name=None) -> dict` | Devuelve la receta de un STYLE PRESET curado o el catálogo si `name=None`. Receta = `{subject_prefix, subject_suffix, style, negative, checkpoint, lora, lora_strength, size, transparent, post, notes}`. Pura, copias profundas. **6 estilos**: **gameboy** (sin LoRA → prompt + post `pixelize` paleta `game-boy` 4 tonos verde), **ghibli** (degrada a `SD15_watercolor_style` gratis instalado + prompt; no hay LoRA Ghibli dedicado ni se descargó nada gated), **pixel-art-retro** (reutiliza `SDXL_pixel-art` SDXL ya instalado → checkpoint `juggernaut_xl_v11` + size 768 + post `pixelize` 16 colores), **cyberpunk-neon** (prompt puro SD1.5, glow magenta/cyan, sin post), **low-poly-flat** (prompt puro SD1.5, facetas/flat shading PS1, sin post, transparent), **cartoon-cel-shaded** (LoRA `SD15_anime_style_box` 0.7 + prompt cel-shaded, sin post, transparent). Extensible: añadir un estilo = una entrada en `_PRESETS`. |
|
||||||
| `comfyui_apply_style_preset_py_ml` | `(preset, subject, *, style=None, negative=None) -> dict` | Traduce un preset + un `subject` a `{name, subject (con prefijo/sufijo), builder_kwargs={style,checkpoint,lora,lora_strength,negative}, size, transparent, post}`. Los `builder_kwargs` hacen `**spread` directo en cualquier builder de sujeto; `size`/`transparent` van aparte (recomendaciones); el caller aplica `post["pixelize"]` al PNG si existe. Pura, no muta el preset; `negative` se mergea (no reemplaza). |
|
| `comfyui_apply_style_preset_py_ml` | `(preset, subject, *, style=None, negative=None) -> dict` | Traduce un preset + un `subject` a `{name, subject (con prefijo/sufijo), builder_kwargs={style,checkpoint,lora,lora_strength,negative}, size, transparent, post}`. Los `builder_kwargs` hacen `**spread` directo en cualquier builder de sujeto; `size`/`transparent` van aparte (recomendaciones); el caller aplica `post["pixelize"]` al PNG si existe. Pura, no muta el preset; `negative` se mergea (no reemplaza). |
|
||||||
|
|
||||||
**Ejemplo canónico (mismo subject, look del juego entero):**
|
**Ejemplo canónico (mismo subject, look del juego entero):**
|
||||||
@@ -184,7 +184,7 @@ gameboy 4 colores verde (`prompt_id 0657e3e3`), ghibli 78 552 colores acuarela
|
|||||||
visiblemente distintos y coherentes. **Gotcha**: en el flujo manual de arriba el `post` no
|
visiblemente distintos y coherentes. **Gotcha**: en el flujo manual de arriba el `post` no
|
||||||
se aplica solo (el caller llama `comfyui_pixelize_image`) — para evitarlo usa el pipeline
|
se aplica solo (el caller llama `comfyui_pixelize_image`) — para evitarlo usa el pipeline
|
||||||
one-shot `comfyui_generate_styled_asset_oneshot` (abajo), que auto-aplica el post. El LoRA y
|
one-shot `comfyui_generate_styled_asset_oneshot` (abajo), que auto-aplica el post. El LoRA y
|
||||||
el checkpoint deben casar de base (pixel-art-xl es SDXL → exige juggernaut); OOM en 8 GB →
|
el checkpoint deben casar de base (SDXL_pixel-art es SDXL → exige juggernaut); OOM en 8 GB →
|
||||||
bajar `size`, NO matar procesos.
|
bajar `size`, NO matar procesos.
|
||||||
|
|
||||||
## Pipelines one-shot (`gamedev-2d`, impuros)
|
## Pipelines one-shot (`gamedev-2d`, impuros)
|
||||||
@@ -236,7 +236,7 @@ from pipelines.comfyui_export_asset_to_godot import comfyui_export_asset_to_godo
|
|||||||
OUT = os.path.expanduser("~/ComfyUI/output")
|
OUT = os.path.expanduser("~/ComfyUI/output")
|
||||||
PROJ = os.path.expanduser("~/gamedev/projects/crossy_road")
|
PROJ = os.path.expanduser("~/gamedev/projects/crossy_road")
|
||||||
|
|
||||||
# 1. Pixelizar un sprite crudo (SDXL+pixel-art-xl) a 16 colores
|
# 1. Pixelizar un sprite crudo (SDXL+SDXL_pixel-art) a 16 colores
|
||||||
px = comfyui_pixelize_image(f"{OUT}/hero_00001_.png", "/tmp/hero_pixel.png",
|
px = comfyui_pixelize_image(f"{OUT}/hero_00001_.png", "/tmp/hero_pixel.png",
|
||||||
downscale=8, colors=16)
|
downscale=8, colors=16)
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ def test_golden_kwargs_spreadable_into_builder():
|
|||||||
assert "KSampler" in cls
|
assert "KSampler" in cls
|
||||||
# El LoRA watercolor del preset aparece en el grafo.
|
# El LoRA watercolor del preset aparece en el grafo.
|
||||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
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():
|
def test_edge_style_override():
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- 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."
|
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
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- 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
|
seed: semilla del KSampler. Fija el mismo seed en la familia de tiers del mismo
|
||||||
logro para que coincidan en composicion. keyword-only.
|
logro para que coincidan en composicion. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime). Solo se
|
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():
|
def test_edge_lora_injected():
|
||||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||||
wf = comfyui_build_achievement_badge_workflow(
|
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"]
|
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||||
assert len(loras) == 1
|
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)
|
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.8)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: upscale_method
|
- name: upscale_method
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ def comfyui_build_asset_variant_workflow(
|
|||||||
deformar). 512 por defecto (SD1.5). keyword-only.
|
deformar). 512 por defecto (SD1.5). keyword-only.
|
||||||
seed: semilla del KSampler. keyword-only.
|
seed: semilla del KSampler. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
upscale_method: metodo del ImageScale ('lanczos', 'bilinear', 'bicubic',
|
upscale_method: metodo del ImageScale ('lanczos', 'bilinear', 'bicubic',
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + mismo subject -> misma ilustracion. keyword-only."
|
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + mismo subject -> misma ilustracion. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: negative
|
- name: negative
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ def comfyui_build_card_art_workflow(
|
|||||||
seed: semilla del KSampler (y de la pasada hires). Misma seed + mismo
|
seed: semilla del KSampler (y de la pasada hires). Misma seed + mismo
|
||||||
subject -> misma ilustracion. keyword-only.
|
subject -> misma ilustracion. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -94,13 +94,13 @@ def test_edge_card_style_in_prompt():
|
|||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_card_art_workflow(
|
wf = comfyui_build_card_art_workflow(
|
||||||
"a phoenix",
|
"a phoenix",
|
||||||
lora="detail_tweaker_sd15.safetensors",
|
lora="SD15_detail_tweaker.safetensors",
|
||||||
lora_strength=0.9,
|
lora_strength=0.9,
|
||||||
hires=False,
|
hires=False,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
||||||
ksampler = _by_class(wf, "KSampler")[0]
|
ksampler = _by_class(wf, "KSampler")[0]
|
||||||
|
|||||||
@@ -114,11 +114,11 @@ def test_edge_negative_isolates_decal():
|
|||||||
|
|
||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_decal_overlay_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||||
|
|
||||||
|
|
||||||
@@ -132,9 +132,9 @@ def test_error_empty_decal():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_decal_overlay_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- 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",
|
# for st in ["fantasy dialogue box", "sci-fi terminal text box, neon glow",
|
||||||
# "visual novel text panel, soft pastel"]:
|
# "visual novel text panel, soft pastel"]:
|
||||||
# wf = comfyui_build_dialogue_box_workflow(st, shape="rounded panel",
|
# 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
|
# 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.
|
# 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.
|
recortable luego por el caller/pipeline. keyword-only.
|
||||||
seed: semilla del KSampler. keyword-only.
|
seed: semilla del KSampler. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime).
|
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():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_dialogue_box_workflow(
|
wf = comfyui_build_dialogue_box_workflow(
|
||||||
"fantasy dialogue box",
|
"fantasy dialogue box",
|
||||||
lora="detail_tweaker_sd15.safetensors",
|
lora="SD15_detail_tweaker.safetensors",
|
||||||
lora_strength=0.9,
|
lora_strength=0.9,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -101,9 +101,9 @@ def test_error_empty_box_style():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_dialogue_box_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ params:
|
|||||||
- name: seed
|
- 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."
|
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
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: weight
|
- name: weight
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ def comfyui_build_emote_workflow(
|
|||||||
mismo character/ref_face -> mismo personaje; variar solo expression
|
mismo character/ref_face -> mismo personaje; variar solo expression
|
||||||
mantiene la identidad y cambia la cara. keyword-only.
|
mantiene la identidad y cambia la cara. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
weight: peso del IPAdapter-FaceID (solo si ref_face). 0.85 = parecido alto;
|
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(
|
wf = comfyui_build_emote_workflow(
|
||||||
"a dark sorceress",
|
"a dark sorceress",
|
||||||
"smug",
|
"smug",
|
||||||
lora="anime_lineart_sd15.safetensors",
|
lora="SD15_anime_lineart.safetensors",
|
||||||
lora_strength=0.8,
|
lora_strength=0.8,
|
||||||
facedetailer=False,
|
facedetailer=False,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||||
|
|
||||||
|
|
||||||
@@ -176,13 +176,13 @@ def test_determinism():
|
|||||||
a = comfyui_build_emote_workflow(
|
a = comfyui_build_emote_workflow(
|
||||||
"a knight woman with red hair",
|
"a knight woman with red hair",
|
||||||
"happy, smiling",
|
"happy, smiling",
|
||||||
lora="anime_lineart_sd15.safetensors",
|
lora="SD15_anime_lineart.safetensors",
|
||||||
seed=7,
|
seed=7,
|
||||||
)
|
)
|
||||||
b = comfyui_build_emote_workflow(
|
b = comfyui_build_emote_workflow(
|
||||||
"a knight woman with red hair",
|
"a knight woman with red hair",
|
||||||
"happy, smiling",
|
"happy, smiling",
|
||||||
lora="anime_lineart_sd15.safetensors",
|
lora="SD15_anime_lineart.safetensors",
|
||||||
seed=7,
|
seed=7,
|
||||||
)
|
)
|
||||||
assert a == b
|
assert a == b
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Misma seed + misma criatura/style -> misma figura; variar solo `variant` da variantes coherentes. keyword-only."
|
desc: "Semilla del KSampler. Misma seed + misma criatura/style -> misma figura; variar solo `variant` da variantes coherentes. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- name: rembg_model
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ def comfyui_build_enemy_creature_workflow(
|
|||||||
seed: semilla del KSampler. Misma seed + misma criatura/style -> misma
|
seed: semilla del KSampler. Misma seed + misma criatura/style -> misma
|
||||||
figura; variar solo `variant` da las variantes coherentes. keyword-only.
|
figura; variar solo `variant` da las variantes coherentes. keyword-only.
|
||||||
lora: LoRA de estilo/criatura opcional en models/loras (ej.
|
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.
|
sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -87,11 +87,11 @@ def test_edge_style_in_prompt():
|
|||||||
|
|
||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_enemy_creature_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -105,9 +105,9 @@ def test_error_empty_creature():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_enemy_creature_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Misma seed + mismo plant/view/style -> misma planta. keyword-only."
|
desc: "Semilla del KSampler. Misma seed + mismo plant/view/style -> misma planta. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- name: rembg_model
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ def comfyui_build_foliage_set_workflow(
|
|||||||
seed: semilla del KSampler. Misma seed + mismo plant/view/style -> misma
|
seed: semilla del KSampler. Misma seed + mismo plant/view/style -> misma
|
||||||
planta. keyword-only.
|
planta. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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.
|
None = sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ def test_edge_negative_rejects_manmade_and_buildings():
|
|||||||
def test_edge_lora_present():
|
def test_edge_lora_present():
|
||||||
"""lora -> LoraLoader presente con la fuerza pasada."""
|
"""lora -> LoraLoader presente con la fuerza pasada."""
|
||||||
wf = comfyui_build_foliage_set_workflow(
|
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,
|
lora_strength=0.8,
|
||||||
)
|
)
|
||||||
assert "LoraLoader" in _classes(wf)
|
assert "LoraLoader" in _classes(wf)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: mode
|
- 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
|
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.
|
forma consistente. Solo aplica al modo vae_encode. keyword-only.
|
||||||
seed: semilla del KSampler. 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.
|
None = sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
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.
|
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.
|
`/mnt/2tb`), esa clave los mapea. Sin ella `ipadapter_file` sale vacio.
|
||||||
- **faceid usa insightface (`buffalo_l`) + la LoRA FaceID.** El UnifiedLoaderFaceID
|
- **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
|
`models/loras/`). `provider='CPU'` por defecto: insightface en CPU no compite por
|
||||||
los 8GB de VRAM; pon `'CUDA'` solo si tienes onnxruntime-gpu instalado.
|
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:
|
- **La referencia debe existir en `input/`.** Es un nombre de archivo, no una ruta:
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ lang: py
|
|||||||
domain: ml
|
domain: ml
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
purity: pure
|
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"
|
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 (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."
|
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]
|
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_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_inject_lora_py_ml, comfyui_inject_controlnet_py_ml]
|
||||||
uses_types: []
|
uses_types: []
|
||||||
@@ -22,7 +22,7 @@ params:
|
|||||||
- name: ckpt_name
|
- name: ckpt_name
|
||||||
desc: "Checkpoint base. Default 'dreamshaper_8.safetensors' (SD1.5 holgado, casa con la LoRA iso SD1.5). keyword-only."
|
desc: "Checkpoint base. Default 'dreamshaper_8.safetensors' (SD1.5 holgado, casa con la LoRA iso SD1.5). keyword-only."
|
||||||
- name: iso_lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza de la LoRA iso sobre model y clip (recomendado 0.9). keyword-only."
|
desc: "Fuerza de la LoRA iso sobre model y clip (recomendado 0.9). keyword-only."
|
||||||
- name: grid_image
|
- name: grid_image
|
||||||
@@ -86,7 +86,7 @@ el prompt se desvíe del ángulo y quieras forzar la rejilla. Para una textura i
|
|||||||
|
|
||||||
## Gotchas
|
## 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`).
|
(ya presente). Es SD1.5: usa un checkpoint SD1.5 (`dreamshaper_8`).
|
||||||
- **`comfyui_inject_controlnet` NO preprocesa**: `grid_image` debe ser una imagen
|
- **`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
|
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
|
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:
|
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
|
2. ControlNet grid (refuerzo opcional): una plantilla de rejilla isometrica
|
||||||
(rombos 2:1) ya preprocesada (canny/lineart) fuerza el layout. Se inyecta con
|
(rombos 2:1) ya preprocesada (canny/lineart) fuerza el layout. Se inyecta con
|
||||||
comfyui_inject_controlnet (legacy ControlNetApply; basta para un grid guia).
|
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",
|
negative: str = "perspective, vanishing point, blurry, low quality",
|
||||||
*,
|
*,
|
||||||
ckpt_name: str = "dreamshaper_8.safetensors",
|
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,
|
lora_strength: float = 0.9,
|
||||||
grid_image: str | None = None,
|
grid_image: str | None = None,
|
||||||
controlnet_name: str = "control_v11p_sd15_canny_fp16.safetensors",
|
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
|
ckpt_name: checkpoint base (default 'dreamshaper_8.safetensors', SD1.5
|
||||||
holgado y casa con la LoRA iso SD1.5). keyword-only.
|
holgado y casa con la LoRA iso SD1.5). keyword-only.
|
||||||
iso_lora: LoRA isometrica en models/loras
|
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).
|
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
|
grid_image: nombre de una plantilla de rejilla isometrica ya preprocesada
|
||||||
(line-art/canny) en input/ del servidor. Si se pasa, inyecta un
|
(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")
|
wf = comfyui_build_isometric_workflow("isometric house, game asset")
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
# Sin grid_image -> sin ControlNet.
|
# Sin grid_image -> sin ControlNet.
|
||||||
assert len(_by_class(wf, "ControlNetApply")) == 0
|
assert len(_by_class(wf, "ControlNetApply")) == 0
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- name: rembg_model
|
||||||
@@ -69,7 +69,7 @@ wf = comfyui_build_item_icon_workflow(
|
|||||||
# Set coherente: misma firma de estilo para cada item del inventario.
|
# Set coherente: misma firma de estilo para cada item del inventario.
|
||||||
# for it in ["iron sword", "gold ring", "ancient book", "wooden shield"]:
|
# for it in ["iron sword", "gold ring", "ancient book", "wooden shield"]:
|
||||||
# wf = comfyui_build_item_icon_workflow(it, style="hand-painted RPG icon",
|
# 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
|
# comfyui_submit_workflow(wf) # -> comfyui_wait_result -> comfyui_fetch_output_image
|
||||||
# Contact-sheet del set: montar los PNG resultantes con comfyui_build_grid.
|
# 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.
|
luego por el caller/pipeline. keyword-only.
|
||||||
seed: semilla del KSampler. keyword-only.
|
seed: semilla del KSampler. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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.
|
None = sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -73,11 +73,11 @@ def test_edge_style_in_prompt():
|
|||||||
|
|
||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_item_icon_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -90,6 +90,6 @@ def test_error_empty_item():
|
|||||||
|
|
||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = 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="detail_tweaker_sd15.safetensors", seed=7)
|
b = comfyui_build_item_icon_workflow("emerald gem", lora="SD15_detail_tweaker.safetensors", seed=7)
|
||||||
assert a == b
|
assert a == b
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: negative
|
- 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]
|
costura. Default 0 (el feathering del pad suele bastar). Se clampa a [0, 64]
|
||||||
(limite de VAEEncodeForInpaint). keyword-only.
|
(limite de VAEEncodeForInpaint). keyword-only.
|
||||||
seed: semilla del KSampler. 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.
|
None = sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -123,11 +123,11 @@ def test_edge_negative_isolates_single_particle():
|
|||||||
|
|
||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_particle_texture_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||||
|
|
||||||
|
|
||||||
@@ -141,9 +141,9 @@ def test_error_empty_particle():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_particle_texture_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ lang: py
|
|||||||
domain: ml
|
domain: ml
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
purity: pure
|
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"
|
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 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)."
|
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]
|
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_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_inject_multi_lora_py_ml]
|
||||||
uses_types: []
|
uses_types: []
|
||||||
@@ -20,15 +20,15 @@ params:
|
|||||||
- name: negative
|
- name: negative
|
||||||
desc: "Prompt negativo. Por defecto evita blur/gradientes/anti-alias que estropean el look pixel."
|
desc: "Prompt negativo. Por defecto evita blur/gradientes/anti-alias que estropean el look pixel."
|
||||||
- name: ckpt_name
|
- 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
|
- 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
|
- 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
|
- 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."
|
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
|
- 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
|
- name: lcm_strength
|
||||||
desc: "Fuerza de la LCM-LoRA sobre model y clip (recomendado 1.0). keyword-only."
|
desc: "Fuerza de la LCM-LoRA sobre model y clip (recomendado 1.0). keyword-only."
|
||||||
- name: steps
|
- name: steps
|
||||||
@@ -47,9 +47,9 @@ params:
|
|||||||
desc: "Scheduler del KSampler. None = default del modo ('sgm_uniform' con LCM, 'normal' sin). keyword-only."
|
desc: "Scheduler del KSampler. None = default del modo ('sgm_uniform' con LCM, 'normal' sin). keyword-only."
|
||||||
- name: filename_prefix
|
- name: filename_prefix
|
||||||
desc: "Prefijo del PNG que SaveImage escribe en output/. keyword-only."
|
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
|
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"
|
test_file_path: "python/functions/ml/comfyui_build_pixelart_workflow_test.py"
|
||||||
file_path: "python/functions/ml/comfyui_build_pixelart_workflow.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"))
|
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
|
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(
|
wf = comfyui_build_pixelart_workflow(
|
||||||
"isometric tiny house, pixel, 32x32 style, vibrant colors",
|
"isometric tiny house, pixel, 32x32 style, vibrant colors",
|
||||||
use_lcm=True,
|
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 lo pegues en la UI.
|
||||||
- **No produce pixel-perfect por sí solo**: deja pixeles irregulares y cientos de
|
- **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).
|
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.
|
`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
|
`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.
|
`--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
|
- 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
|
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
|
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
|
tamano irregular y cientos de colores: el pixel-perfect (Fase 2) lo hace
|
||||||
`comfyui_pixelize_image` (downscale nearest + cuantizacion), NO este workflow.
|
`comfyui_pixelize_image` (downscale nearest + cuantizacion), NO este workflow.
|
||||||
|
|
||||||
Compone funciones existentes del registry, no reescribe el grafo:
|
Compone funciones existentes del registry, no reescribe el grafo:
|
||||||
- comfyui_build_txt2img_workflow -> base SDXL txt2img
|
- 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):
|
class_types/params verificados contra /object_info del servidor (8GB lowvram):
|
||||||
CheckpointLoaderSimple, LoraLoader, CLIPTextEncode, EmptyLatentImage,
|
CheckpointLoaderSimple, LoraLoader, CLIPTextEncode, EmptyLatentImage,
|
||||||
KSampler (sampler 'lcm', scheduler 'sgm_uniform' presentes), VAEDecode, SaveImage.
|
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.
|
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",
|
negative: str = "blurry, jpeg artifacts, gradient, smooth shading, anti-aliasing",
|
||||||
*,
|
*,
|
||||||
ckpt_name: str = "juggernaut_xl_v11.safetensors",
|
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,
|
lora_strength: float = 1.2,
|
||||||
use_lcm: bool = True,
|
use_lcm: bool = True,
|
||||||
lcm_lora: str = "lcm-lora-sdxl.safetensors",
|
lcm_lora: str = "SDXL_lcm-lora.safetensors",
|
||||||
lcm_strength: float = 1.0,
|
lcm_strength: float = 1.0,
|
||||||
steps: int | None = None,
|
steps: int | None = None,
|
||||||
cfg: float | 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,
|
negative: prompt negativo (por defecto evita blur/gradientes/anti-alias,
|
||||||
que estropean el look pixel).
|
que estropean el look pixel).
|
||||||
ckpt_name: checkpoint SDXL base (default 'juggernaut_xl_v11.safetensors',
|
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.
|
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].
|
Se clampa a [0.0, 2.0].
|
||||||
use_lcm: si True encadena la LCM-LoRA SDXL y usa los defaults rapidos
|
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
|
(8 steps, cfg 1.5, sampler 'lcm', scheduler 'sgm_uniform'); si False
|
||||||
@@ -74,8 +74,8 @@ def comfyui_build_pixelart_workflow(
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict en API format listo para comfyui_submit_workflow, con el
|
dict en API format listo para comfyui_submit_workflow, con el
|
||||||
CheckpointLoaderSimple, 1 LoraLoader (pixel-art-xl) o 2 (pixel-art-xl +
|
CheckpointLoaderSimple, 1 LoraLoader (SDXL_pixel-art) o 2 (SDXL_pixel-art +
|
||||||
lcm-lora-sdxl si use_lcm), KSampler con los params del modo y SaveImage.
|
SDXL_lcm-lora si use_lcm), KSampler con los params del modo y SaveImage.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: si positive esta vacio.
|
ValueError: si positive esta vacio.
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ def _ksampler(wf):
|
|||||||
def test_golden_lcm_two_loras():
|
def test_golden_lcm_two_loras():
|
||||||
wf = comfyui_build_pixelart_workflow("isometric house, pixel, 32x32 style", use_lcm=True)
|
wf = comfyui_build_pixelart_workflow("isometric house, pixel, 32x32 style", use_lcm=True)
|
||||||
cls = _classes(wf)
|
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"]
|
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||||
assert len(loras) == 2
|
assert len(loras) == 2
|
||||||
names = {n["inputs"]["lora_name"] for n in loras}
|
names = {n["inputs"]["lora_name"] for n in loras}
|
||||||
assert names == {"pixel-art-xl.safetensors", "lcm-lora-sdxl.safetensors"}
|
assert names == {"SDXL_pixel-art.safetensors", "SDXL_lcm-lora.safetensors"}
|
||||||
px = next(n for n in loras if n["inputs"]["lora_name"] == "pixel-art-xl.safetensors")
|
px = next(n for n in loras if n["inputs"]["lora_name"] == "SDXL_pixel-art.safetensors")
|
||||||
assert px["inputs"]["strength_model"] == 1.2
|
assert px["inputs"]["strength_model"] == 1.2
|
||||||
# KSampler con defaults LCM.
|
# KSampler con defaults LCM.
|
||||||
ks = _ksampler(wf)["inputs"]
|
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)
|
wf = comfyui_build_pixelart_workflow("a pixel sword", use_lcm=False)
|
||||||
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||||
assert len(loras) == 1
|
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"]
|
ks = _ksampler(wf)["inputs"]
|
||||||
assert ks["steps"] == 25 and ks["cfg"] == 7.0
|
assert ks["steps"] == 25 and ks["cfg"] == 7.0
|
||||||
assert ks["sampler_name"] == "euler" and ks["scheduler"] == "normal"
|
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
|
assert ks["steps"] == 12 and ks["cfg"] == 2.0
|
||||||
px = next(
|
px = next(
|
||||||
n for n in wf.values()
|
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]
|
assert px["inputs"]["strength_model"] == 2.0 # clamp a [0,2]
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler (y del sampler del FaceDetailer). Misma seed + mismo character/ref_face -> mismo retrato. keyword-only."
|
desc: "Semilla del KSampler (y del sampler del FaceDetailer). Misma seed + mismo character/ref_face -> mismo retrato. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: weight
|
- name: weight
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ def comfyui_build_portrait_avatar_workflow(
|
|||||||
seed: semilla del KSampler (y del sampler del FaceDetailer). Misma seed +
|
seed: semilla del KSampler (y del sampler del FaceDetailer). Misma seed +
|
||||||
mismo character/ref_face -> mismo retrato. keyword-only.
|
mismo character/ref_face -> mismo retrato. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
weight: peso del IPAdapter-FaceID (solo si ref_face). 0.85 = parecido alto;
|
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():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_portrait_avatar_workflow(
|
wf = comfyui_build_portrait_avatar_workflow(
|
||||||
"a dark sorceress",
|
"a dark sorceress",
|
||||||
lora="anime_lineart_sd15.safetensors",
|
lora="SD15_anime_lineart.safetensors",
|
||||||
lora_strength=0.8,
|
lora_strength=0.8,
|
||||||
facedetailer=False,
|
facedetailer=False,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||||
|
|
||||||
|
|
||||||
@@ -135,9 +135,9 @@ def test_error_empty_character():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_portrait_avatar_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- name: rembg_model
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ def comfyui_build_projectile_workflow(
|
|||||||
keyword-only.
|
keyword-only.
|
||||||
seed: semilla del KSampler. keyword-only.
|
seed: semilla del KSampler. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime). Solo
|
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():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_projectile_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -148,9 +148,9 @@ def test_error_empty_projectile():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_projectile_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Misma seed + mismo prop/style -> mismo objeto. keyword-only."
|
desc: "Semilla del KSampler. Misma seed + mismo prop/style -> mismo objeto. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- name: rembg_model
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ def comfyui_build_prop_object_workflow(
|
|||||||
seed: semilla del KSampler. Misma seed + mismo prop/style -> mismo objeto.
|
seed: semilla del KSampler. Misma seed + mismo prop/style -> mismo objeto.
|
||||||
keyword-only.
|
keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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.
|
None = sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -102,12 +102,12 @@ def test_edge_world_object_not_inventory_icon():
|
|||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_prop_object_workflow(
|
wf = comfyui_build_prop_object_workflow(
|
||||||
"ornate vase",
|
"ornate vase",
|
||||||
lora="isometric_game_assets_sd15.safetensors",
|
lora="SD15_isometric_game_assets.safetensors",
|
||||||
lora_strength=0.9,
|
lora_strength=0.9,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -127,9 +127,9 @@ def test_error_empty_prop():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_prop_object_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ def test_edge_lora_injected_when_requested():
|
|||||||
wf_no = comfyui_build_rune_glyph_workflow("ward symbol")
|
wf_no = comfyui_build_rune_glyph_workflow("ward symbol")
|
||||||
assert "LoraLoader" not in _classes(wf_no)
|
assert "LoraLoader" not in _classes(wf_no)
|
||||||
wf_lora = comfyui_build_rune_glyph_workflow(
|
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)
|
assert "LoraLoader" in _classes(wf_lora)
|
||||||
ll = next(n for n in wf_lora.values() if n["class_type"] == "LoraLoader")
|
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():
|
def test_edge_material_lora_before_tile():
|
||||||
wf = comfyui_build_seamless_tile_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
assert len(loras) == 1
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Fija el mismo seed en el par unlocked/locked del mismo talento para que coincidan. keyword-only."
|
desc: "Semilla del KSampler. Fija el mismo seed en el par unlocked/locked del mismo talento para que coincidan. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- 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
|
seed: semilla del KSampler. Fija el mismo seed en el par unlocked/locked del
|
||||||
mismo talento para que coincidan. keyword-only.
|
mismo talento para que coincidan. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime). Solo se
|
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():
|
def test_edge_lora_injected():
|
||||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||||
wf = comfyui_build_skill_tree_node_workflow(
|
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"]
|
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||||
assert len(loras) == 1
|
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)
|
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.8)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + misma scene -> misma ilustracion. keyword-only."
|
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + misma scene -> misma ilustracion. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: negative
|
- 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
|
seed: semilla del KSampler (y de la pasada hires). Misma seed + misma scene
|
||||||
-> misma ilustracion. keyword-only.
|
-> misma ilustracion. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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. Encadena la identidad visual del juego. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -97,13 +97,13 @@ def test_edge_mood_in_prompt():
|
|||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_splash_art_workflow(
|
wf = comfyui_build_splash_art_workflow(
|
||||||
"a knight raising a banner on a hill",
|
"a knight raising a banner on a hill",
|
||||||
lora="concept_art_sd15.safetensors",
|
lora="SD15_concept_art.safetensors",
|
||||||
lora_strength=0.9,
|
lora_strength=0.9,
|
||||||
hires=False,
|
hires=False,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
||||||
ksampler = _by_class(wf, "KSampler")[0]
|
ksampler = _by_class(wf, "KSampler")[0]
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: preprocess
|
- 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
|
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.
|
normaliza el boceto a esta resolucion. 512 por defecto (SD1.5). keyword-only.
|
||||||
seed: semilla del KSampler. 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.
|
None = sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. 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
|
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():
|
def test_edge_char_lora():
|
||||||
wf = comfyui_build_sprite_sheet_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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():
|
def test_error_empty_subject():
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- 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.
|
# Barra de estados coherente: misma firma de estilo para cada efecto.
|
||||||
# for fx in ["burning", "frozen", "shield", "regeneration", "stun", "speed boost"]:
|
# 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",
|
# 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
|
# comfyui_submit_workflow(wf) # -> comfyui_wait_result -> comfyui_fetch_output_image
|
||||||
# Atlas de estados: montar los PNG resultantes con comfyui_build_grid.
|
# 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.
|
recortable luego por el caller/pipeline. keyword-only.
|
||||||
seed: semilla del KSampler. keyword-only.
|
seed: semilla del KSampler. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime).
|
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime).
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ def test_edge_effect_reflected():
|
|||||||
def test_edge_lora_injected():
|
def test_edge_lora_injected():
|
||||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||||
wf = comfyui_build_status_effect_icon_workflow(
|
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"]
|
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||||
assert len(loras) == 1
|
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)
|
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.8)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Misma seed + misma structure/view/style -> mismo edificio. keyword-only."
|
desc: "Semilla del KSampler. Misma seed + misma structure/view/style -> mismo edificio. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- 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.
|
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;
|
- **`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
|
`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.
|
fija mejor el ángulo 2:1 que solo el prompt.
|
||||||
- **Coherencia del set = mismos parámetros**: si cambias `view`/`style`/`checkpoint`/`lora`/
|
- **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`.
|
`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
|
seed: semilla del KSampler. Misma seed + misma structure/view/style -> mismo
|
||||||
edificio. keyword-only.
|
edificio. keyword-only.
|
||||||
lora: LoRA de estilo/isometrica opcional en models/loras (ej.
|
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
|
Para escenarios isometricos coherentes, la LoRA iso ayuda a fijar el angulo
|
||||||
2:1. None = sin LoRA. keyword-only.
|
2:1. None = sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
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():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_structure_workflow(
|
wf = comfyui_build_structure_workflow(
|
||||||
"wizard tower",
|
"wizard tower",
|
||||||
lora="isometric_game_assets_sd15.safetensors",
|
lora="SD15_isometric_game_assets.safetensors",
|
||||||
lora_strength=0.9,
|
lora_strength=0.9,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -148,9 +148,9 @@ def test_error_empty_structure():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_structure_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -121,11 +121,11 @@ def test_edge_negative_allows_text():
|
|||||||
def test_edge_lora_injected():
|
def test_edge_lora_injected():
|
||||||
"""lora -> LoraLoader presente con la fuerza dada."""
|
"""lora -> LoraLoader presente con la fuerza dada."""
|
||||||
wf = comfyui_build_title_lettering_workflow(
|
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"]
|
loras = [n for n in wf.values() if n["class_type"] == "LoraLoader"]
|
||||||
assert len(loras) == 1
|
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)
|
assert loras[0]["inputs"]["strength_model"] == pytest.approx(0.7)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Misma seed + misma subject/style -> misma figura; variar solo `direction` da las vistas coherentes de movimiento. keyword-only."
|
desc: "Semilla del KSampler. Misma seed + misma subject/style -> misma figura; variar solo `direction` da las vistas coherentes de movimiento. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- name: rembg_model
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ def comfyui_build_topdown_sprite_workflow(
|
|||||||
figura; variar solo `direction` da las vistas coherentes de movimiento.
|
figura; variar solo `direction` da las vistas coherentes de movimiento.
|
||||||
keyword-only.
|
keyword-only.
|
||||||
lora: LoRA de estilo/top-down opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime). Solo
|
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():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_topdown_sprite_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -129,9 +129,9 @@ def test_error_empty_subject():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_topdown_sprite_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Misma seed + mismo hazard/view/style -> misma trampa. keyword-only."
|
desc: "Semilla del KSampler. Misma seed + mismo hazard/view/style -> misma trampa. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- 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.
|
seed: semilla del KSampler. Misma seed + mismo hazard/view/style -> misma trampa.
|
||||||
keyword-only.
|
keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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.
|
sin LoRA. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -118,11 +118,11 @@ def test_edge_negative_rejects_living_character():
|
|||||||
|
|
||||||
def test_edge_lora_injected():
|
def test_edge_lora_injected():
|
||||||
wf = comfyui_build_trap_hazard_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. keyword-only."
|
desc: "Semilla del KSampler. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- 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.
|
# HUD coherente: misma firma de estilo para cada pieza de la interfaz.
|
||||||
# for el in ["wooden button", "ornate frame", "mana orb", "menu cursor"]:
|
# for el in ["wooden button", "ornate frame", "mana orb", "menu cursor"]:
|
||||||
# wf = comfyui_build_ui_hud_workflow(el, ui_style="fantasy game UI",
|
# 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
|
# comfyui_submit_workflow(wf) # -> comfyui_wait_result -> comfyui_fetch_output_image
|
||||||
# Atlas del HUD: montar los PNG resultantes con comfyui_build_grid.
|
# 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.
|
recortable luego por el caller/pipeline. keyword-only.
|
||||||
seed: semilla del KSampler. keyword-only.
|
seed: semilla del KSampler. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime).
|
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():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_ui_hud_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -91,6 +91,6 @@ def test_error_empty_element():
|
|||||||
|
|
||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = 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="detail_tweaker_sd15.safetensors", seed=7)
|
b = comfyui_build_ui_hud_workflow("menu cursor", lora="SD15_detail_tweaker.safetensors", seed=7)
|
||||||
assert a == b
|
assert a == b
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler. Misma seed + mismo vehicle/view/style -> mismo vehiculo. keyword-only."
|
desc: "Semilla del KSampler. Misma seed + mismo vehicle/view/style -> mismo vehiculo. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: rembg_model
|
- name: rembg_model
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ def comfyui_build_vehicle_mount_workflow(
|
|||||||
seed: semilla del KSampler. Misma seed + mismo vehicle/view/style -> mismo
|
seed: semilla del KSampler. Misma seed + mismo vehicle/view/style -> mismo
|
||||||
vehiculo. keyword-only.
|
vehiculo. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej.
|
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. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -98,11 +98,11 @@ def test_edge_style_in_prompt():
|
|||||||
|
|
||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_vehicle_mount_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
|
|
||||||
|
|
||||||
@@ -116,9 +116,9 @@ def test_error_empty_vehicle():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_vehicle_mount_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def test_edge_open_loop():
|
|||||||
|
|
||||||
def test_edge_lora_fx():
|
def test_edge_lora_fx():
|
||||||
wf = comfyui_build_vfx_spritesheet_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
assert len(loras) == 1
|
||||||
|
|||||||
@@ -119,11 +119,11 @@ def test_edge_negative_isolates_layer():
|
|||||||
|
|
||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_weather_overlay_workflow(
|
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")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.8
|
||||||
|
|
||||||
|
|
||||||
@@ -137,9 +137,9 @@ def test_error_empty_weather():
|
|||||||
|
|
||||||
def test_determinism():
|
def test_determinism():
|
||||||
a = comfyui_build_weather_overlay_workflow(
|
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(
|
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
|
assert a == b
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ params:
|
|||||||
- name: seed
|
- name: seed
|
||||||
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + misma region -> mismo mapa. keyword-only."
|
desc: "Semilla del KSampler (y de la pasada hires). Misma seed + misma region -> mismo mapa. keyword-only."
|
||||||
- name: lora
|
- 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
|
- name: lora_strength
|
||||||
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
desc: "Fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0]. keyword-only."
|
||||||
- name: negative
|
- 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
|
seed: semilla del KSampler (y de la pasada hires). Misma seed + misma region
|
||||||
-> mismo mapa. keyword-only.
|
-> mismo mapa. keyword-only.
|
||||||
lora: LoRA de estilo opcional en models/loras (ej. 'cartography_sd15.safe-
|
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.
|
identidad visual del mapa del juego. keyword-only.
|
||||||
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
|
||||||
keyword-only.
|
keyword-only.
|
||||||
|
|||||||
@@ -101,13 +101,13 @@ def test_edge_map_style_in_prompt():
|
|||||||
def test_edge_lora_reflected():
|
def test_edge_lora_reflected():
|
||||||
wf = comfyui_build_world_map_workflow(
|
wf = comfyui_build_world_map_workflow(
|
||||||
"an archipelago of volcanic islands",
|
"an archipelago of volcanic islands",
|
||||||
lora="cartography_sd15.safetensors",
|
lora="SD15_cartography.safetensors",
|
||||||
lora_strength=0.9,
|
lora_strength=0.9,
|
||||||
hires=False,
|
hires=False,
|
||||||
)
|
)
|
||||||
loras = _by_class(wf, "LoraLoader")
|
loras = _by_class(wf, "LoraLoader")
|
||||||
assert len(loras) == 1
|
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
|
assert loras[0]["inputs"]["strength_model"] == 0.9
|
||||||
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
# Con lora el KSampler.model ya NO viene del checkpoint directo.
|
||||||
ksampler = _by_class(wf, "KSampler")[0]
|
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(
|
mixed = comfyui_compose_capabilities(
|
||||||
base,
|
base,
|
||||||
loras=[
|
loras=[
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5},
|
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||||
],
|
],
|
||||||
facedetailer={"denoise": 0.45},
|
facedetailer={"denoise": 0.45},
|
||||||
# controlnet=..., ipadapter=..., hires=... -> None = desactivadas
|
# controlnet=..., ipadapter=..., hires=... -> None = desactivadas
|
||||||
|
|||||||
@@ -195,8 +195,8 @@ if __name__ == "__main__":
|
|||||||
mixed = comfyui_compose_capabilities(
|
mixed = comfyui_compose_capabilities(
|
||||||
base,
|
base,
|
||||||
loras=[
|
loras=[
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5},
|
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||||
],
|
],
|
||||||
facedetailer={"denoise": 0.45},
|
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)."
|
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."
|
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
|
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"
|
test_file_path: "python/functions/ml/comfyui_get_gamedev_style_preset_test.py"
|
||||||
file_path: "python/functions/ml/comfyui_get_gamedev_style_preset.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_submit_workflow`/`comfyui_wait_result`/`comfyui_fetch_output_image` +
|
||||||
`comfyui_pixelize_image`.
|
`comfyui_pixelize_image`.
|
||||||
- **El checkpoint y el LoRA deben casar de base**: `pixel-art-retro` usa el LoRA SDXL
|
- **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,
|
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.
|
descargalo a `models/loras` y verifica su base antes.
|
||||||
- **ghibli no usa un LoRA Ghibli dedicado**: no hay ninguno instalado y no se descargo
|
- **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
|
prompt Ghibli para el look pintado/acuarela. Un LoRA Ghibli especifico de Civitai
|
||||||
mejoraria el parecido facial — pendiente humano.
|
mejoraria el parecido facial — pendiente humano.
|
||||||
- **gameboy se resuelve por POST, no por LoRA**: sin LoRA; el look DMG de 4 tonos verde lo
|
- **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
|
aplicar el post (`preset["post"]["pixelize"]`) o solo vera un sprite monocromo-ish sin
|
||||||
la paleta sellada.
|
la paleta sellada.
|
||||||
- **Modelos verificados en el servidor** (8GB lowvram, modelos en `/mnt/2tb`): si cambias
|
- **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
|
de PC valida que `dreamshaper_8`, `juggernaut_xl_v11`, `SDXL_pixel-art` y
|
||||||
`watercolor_style_sd15` existan (`GET /object_info/CheckpointLoaderSimple` y `/LoraLoader`).
|
`SD15_watercolor_style` existan (`GET /object_info/CheckpointLoaderSimple` y `/LoraLoader`).
|
||||||
|
|
||||||
## Capability growth log
|
## Capability growth log
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import copy
|
|||||||
|
|
||||||
# Modelos verificados presentes en el servidor (8GB lowvram, modelos en /mnt/2tb):
|
# Modelos verificados presentes en el servidor (8GB lowvram, modelos en /mnt/2tb):
|
||||||
# checkpoints: dreamshaper_8 (SD1.5), juggernaut_xl_v11 (SDXL)
|
# 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
|
# 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).
|
# que el `checkpoint` casa con su base (un LoRA SDXL exige checkpoint SDXL).
|
||||||
_PRESETS: dict[str, dict] = {
|
_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
|
# 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
|
# 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. Sin post-proceso (es ilustracion pintada, no pixelart).
|
||||||
"ghibli": {
|
"ghibli": {
|
||||||
"name": "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",
|
"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",
|
"negative": "photo, photorealistic, 3d render, harsh shadows, pixel art, lowres, deformed, text, watermark, signature",
|
||||||
"checkpoint": "dreamshaper_8.safetensors",
|
"checkpoint": "dreamshaper_8.safetensors",
|
||||||
"lora": "watercolor_style_sd15.safetensors",
|
"lora": "SD15_watercolor_style.safetensors",
|
||||||
"lora_strength": 0.7,
|
"lora_strength": 0.7,
|
||||||
"size": 512,
|
"size": 512,
|
||||||
"transparent": False,
|
"transparent": False,
|
||||||
"post": {},
|
"post": {},
|
||||||
"notes": (
|
"notes": (
|
||||||
"No hay LoRA Ghibli dedicado instalado y no se descargo ninguno gated/de pago "
|
"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 "
|
"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 "
|
"Ghibli especifico de Civitai mejoraria el parecido facial — pendiente humano si "
|
||||||
"se quiere. transparent=False para conservar el fondo acuarela."
|
"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
|
# (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).
|
# pixelize a 16 colores sella los pixeles duros (el LoRA da el estilo, el post el grid).
|
||||||
"pixel-art-retro": {
|
"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",
|
"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",
|
"negative": "blurry, smooth, photorealistic, 3d render, realistic, antialiasing, soft, gradient, noise",
|
||||||
"checkpoint": "juggernaut_xl_v11.safetensors",
|
"checkpoint": "juggernaut_xl_v11.safetensors",
|
||||||
"lora": "pixel-art-xl.safetensors",
|
"lora": "SDXL_pixel-art.safetensors",
|
||||||
"lora_strength": 1.0,
|
"lora_strength": 1.0,
|
||||||
"size": 768,
|
"size": 768,
|
||||||
"transparent": False,
|
"transparent": False,
|
||||||
@@ -128,8 +128,8 @@ _PRESETS: dict[str, dict] = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notes": (
|
"notes": (
|
||||||
"Reutiliza pixel-art-xl.safetensors (SDXL, ya instalado) -> requiere checkpoint "
|
"Reutiliza SDXL_pixel-art.safetensors (SDXL, ya instalado) -> requiere checkpoint "
|
||||||
"SDXL juggernaut_xl_v11 y size 768 (a 512 SDXL+pixel-art-xl pierde calidad). El "
|
"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 "
|
"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."
|
"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,
|
"transparent": True,
|
||||||
"post": {},
|
"post": {},
|
||||||
"notes": (
|
"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 "
|
"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 "
|
"(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 "
|
"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
|
# 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).
|
# 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).
|
# Sin post (es ilustración vectorial limpia, no pixelart).
|
||||||
"cartoon-cel-shaded": {
|
"cartoon-cel-shaded": {
|
||||||
"name": "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",
|
"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",
|
"negative": "photorealistic, soft shading, gradient, realistic texture, painterly, blurry, noisy, pixel art, lowres, grainy, deformed, text, watermark, signature",
|
||||||
"checkpoint": "dreamshaper_8.safetensors",
|
"checkpoint": "dreamshaper_8.safetensors",
|
||||||
"lora": "anime_style_box_sd15.safetensors",
|
"lora": "SD15_anime_style_box.safetensors",
|
||||||
"lora_strength": 0.7,
|
"lora_strength": 0.7,
|
||||||
"size": 512,
|
"size": 512,
|
||||||
"transparent": True,
|
"transparent": True,
|
||||||
"post": {},
|
"post": {},
|
||||||
"notes": (
|
"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, "
|
"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 "
|
"sombras duras por celdas, colores planos saturados). SD1.5 (dreamshaper_8). Sin "
|
||||||
"post: el look vectorial limpio no necesita pixelize. transparent=True para recortar "
|
"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():
|
def test_golden_pixel_retro_uses_sdxl_lora():
|
||||||
r = comfyui_get_gamedev_style_preset("pixel-art-retro")
|
r = comfyui_get_gamedev_style_preset("pixel-art-retro")
|
||||||
# Reutiliza pixel-art-xl (SDXL) -> checkpoint SDXL + size mayor + pixelize.
|
# Reutiliza SDXL_pixel-art (SDXL) -> checkpoint SDXL + size mayor + pixelize.
|
||||||
assert r["lora"] == "pixel-art-xl.safetensors"
|
assert r["lora"] == "SDXL_pixel-art.safetensors"
|
||||||
assert r["checkpoint"] == "juggernaut_xl_v11.safetensors"
|
assert r["checkpoint"] == "juggernaut_xl_v11.safetensors"
|
||||||
assert r["size"] >= 768
|
assert r["size"] >= 768
|
||||||
assert "pixelize" in r["post"]
|
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():
|
def test_golden_ghibli_degrades_to_watercolor_lora():
|
||||||
r = comfyui_get_gamedev_style_preset("ghibli")
|
r = comfyui_get_gamedev_style_preset("ghibli")
|
||||||
# Sin LoRA Ghibli dedicado -> watercolor instalado + prompt; sin post pixelize.
|
# 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 r["post"] == {}
|
||||||
assert "ghibli" in r["style"].lower()
|
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
|
from ml.comfyui_inject_ipadapter import comfyui_inject_ipadapter
|
||||||
|
|
||||||
base = comfyui_build_txt2img_workflow("dreamshaper_8.safetensors", "portrait of a knight")
|
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)
|
wf = comfyui_inject_ipadapter(wf, "hero_face.png", mode="faceid", weight=0.9)
|
||||||
# KSampler.model viene de IPAdapterFaceID(model=ultimo LoraLoader, image=hero_face)
|
# 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")
|
base = comfyui_build_txt2img_workflow("dreamshaper_8.safetensors", "a robot, 3D Render Style")
|
||||||
wf = comfyui_inject_multi_lora(base, [
|
wf = comfyui_inject_multi_lora(base, [
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
{"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
|
# 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(
|
wf = comfyui_inject_multi_lora(
|
||||||
base,
|
base,
|
||||||
[
|
[
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
print(json.dumps(wf, indent=2))
|
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"))
|
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
|
||||||
from ml.comfyui_pixelize_image import comfyui_pixelize_image
|
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(
|
res = comfyui_pixelize_image(
|
||||||
os.path.expanduser("~/ComfyUI/output/pixelart_00001_.png"),
|
os.path.expanduser("~/ComfyUI/output/pixelart_00001_.png"),
|
||||||
"/tmp/hero_pixel.png",
|
"/tmp/hero_pixel.png",
|
||||||
@@ -58,7 +58,7 @@ comfyui_pixelize_image("/tmp/hero_pixel.png", "/tmp/hero_gb.png",
|
|||||||
|
|
||||||
## Cuando usarla
|
## 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 colapsar el grid borroso a pixeles duros y limitar la paleta. Tambien sirve
|
||||||
para "pixelizar" cualquier imagen (sprite, render, foto) a estetica retro sin
|
para "pixelizar" cualquier imagen (sprite, render, foto) a estetica retro sin
|
||||||
tocar la GPU. Para llevar el resultado a Godot con filtro Nearest:
|
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 /
|
pixel duro) -> cuantizacion a N colores o a una paleta fija (NES / Game Boy /
|
||||||
PICO-8) -> opcional re-upscale nearest conservando los pixeles duros.
|
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`
|
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
|
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).
|
lectura/escritura de disco (mismo patron que comfyui_build_grid).
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ def test_solo_loras_encadena():
|
|||||||
out = comfyui_compose_capabilities(
|
out = comfyui_compose_capabilities(
|
||||||
base,
|
base,
|
||||||
loras=[
|
loras=[
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5},
|
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert_api_format(out)
|
assert_api_format(out)
|
||||||
@@ -54,7 +54,7 @@ def test_solo_loras_encadena():
|
|||||||
def test_loras_mas_facedetailer():
|
def test_loras_mas_facedetailer():
|
||||||
out = comfyui_compose_capabilities(
|
out = comfyui_compose_capabilities(
|
||||||
_base(),
|
_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},
|
facedetailer={"denoise": 0.45},
|
||||||
)
|
)
|
||||||
assert_api_format(out)
|
assert_api_format(out)
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ res = comfyui_generate_mixed_oneshot(
|
|||||||
checkpoint="dreamshaper_8.safetensors",
|
checkpoint="dreamshaper_8.safetensors",
|
||||||
capabilities={
|
capabilities={
|
||||||
"loras": [
|
"loras": [
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5},
|
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||||
],
|
],
|
||||||
"facedetailer": {"denoise": 0.45},
|
"facedetailer": {"denoise": 0.45},
|
||||||
# "ipadapter": {"ref_image": "face.png", "mode": "faceid"}, # activar/desactivar
|
# "ipadapter": {"ref_image": "face.png", "mode": "faceid"}, # activar/desactivar
|
||||||
|
|||||||
@@ -210,8 +210,8 @@ if __name__ == "__main__":
|
|||||||
checkpoint="dreamshaper_8.safetensors",
|
checkpoint="dreamshaper_8.safetensors",
|
||||||
capabilities={
|
capabilities={
|
||||||
"loras": [
|
"loras": [
|
||||||
{"name": "3d_render_redmond_sd15.safetensors", "strength_model": 0.9},
|
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||||
{"name": "detail_tweaker_sd15.safetensors", "strength_model": 0.5},
|
{"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5},
|
||||||
],
|
],
|
||||||
"facedetailer": {"denoise": 0.45},
|
"facedetailer": {"denoise": 0.45},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -66,10 +66,10 @@ def test_build_only_preset_drives_workflow():
|
|||||||
|
|
||||||
|
|
||||||
def test_build_only_lora_preset_injects_lora():
|
def test_build_only_lora_preset_injects_lora():
|
||||||
# cartoon-cel-shaded usa anime_style_box_sd15 -> el workflow debe inyectar el LoRA
|
# cartoon-cel-shaded usa SD15_anime_style_box -> el workflow debe inyectar el LoRA
|
||||||
built = styled_asset_build_only("enemy_creature", "goblin", "cartoon-cel-shaded", seed=1)
|
built = styled_asset_build_only("enemy_creature", "goblin", "cartoon-cel-shaded", seed=1)
|
||||||
blob = json.dumps(built["workflow"])
|
blob = json.dumps(built["workflow"])
|
||||||
assert "anime_style_box_sd15.safetensors" in blob
|
assert "SD15_anime_style_box.safetensors" in blob
|
||||||
assert any(n.get("class_type") == "LoraLoader" for n in built["workflow"].values())
|
assert any(n.get("class_type") == "LoraLoader" for n in built["workflow"].values())
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -114,9 +114,22 @@ def _server_models(server):
|
|||||||
|
|
||||||
|
|
||||||
def _norm(name):
|
def _norm(name):
|
||||||
"""Normaliza un nombre de modelo para comparar (sin ext, sin separadores)."""
|
"""Normaliza un nombre de modelo para comparar (sin ext, sin separadores).
|
||||||
|
|
||||||
|
Ignora el token de arquitectura (SD15/SDXL/XL/FLUX) lo lleve como prefijo
|
||||||
|
(convencion nueva: `SDXL_detail_tweaker`) o como sufijo (recetas civitai:
|
||||||
|
`Detail-Tweaker XL`), para que el match sea robusto al reordenado del token.
|
||||||
|
"""
|
||||||
base = os.path.splitext(str(name))[0].lower()
|
base = os.path.splitext(str(name))[0].lower()
|
||||||
return re.sub(r"[^a-z0-9]", "", base)
|
s = re.sub(r"[^a-z0-9]", "", base)
|
||||||
|
for tok in ("sdxl", "sd15", "flux"):
|
||||||
|
if s.startswith(tok):
|
||||||
|
s = s[len(tok):]
|
||||||
|
if s.endswith(tok):
|
||||||
|
s = s[: -len(tok)]
|
||||||
|
if s.endswith("xl"): # 'xl' suelto como sufijo de arquitectura
|
||||||
|
s = s[:-2]
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
def _find_installed(name, installed):
|
def _find_installed(name, installed):
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ def test_pick_checkpoint_familia_y_exacto():
|
|||||||
|
|
||||||
|
|
||||||
def test_find_installed_match_normalizado():
|
def test_find_installed_match_normalizado():
|
||||||
installed = ["detail_tweaker_xl.safetensors", "watercolor_style_sd15.safetensors"]
|
installed = ["SDXL_detail_tweaker.safetensors", "SD15_watercolor_style.safetensors"]
|
||||||
# match normalizado (ignora separadores/ext/case)
|
# match normalizado (ignora separadores/ext/case)
|
||||||
assert _find_installed("Detail-Tweaker XL", installed) == "detail_tweaker_xl.safetensors"
|
assert _find_installed("Detail-Tweaker XL", installed) == "SDXL_detail_tweaker.safetensors"
|
||||||
# no instalado -> None
|
# no instalado -> None
|
||||||
assert _find_installed("LoRA Inexistente 9000", installed) is None
|
assert _find_installed("LoRA Inexistente 9000", installed) is None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user