feat(ml): modelos con prefijo de categoría (IMG_/VIDEO_/3D_) + refs actualizadas
Renombra los 13 checkpoints/diffusion models de ComfyUI prefijando la
categoría al inicio del nombre, para que en el dropdown de carga el usuario
distinga de inmediato imagen/vídeo/3D y no cargue un modelo en el nodo
equivocado. Misma operación que se hizo con los LoRAs (report 0197) pero
sobre los modelos.
Clasificación:
- IMG_: dreamshaper_8, juggernaut_xl_v11, v1-5-pruned-emaonly-fp16,
flux1-dev-fp8-e4m3fn, flux1-schnell-fp8-e4m3fn
- VIDEO_: svd, ltx-video-2b-v0.9.5, wan2.1_t2v_1.3B_fp16
- 3D_: stable_zero123, sv3d_p, hunyuan3d-dit-v2-mini, hunyuan3d-dit-v2-mv,
hy3dgen/hunyuan3d-dit-v2-0-fp16 (mantiene subcarpeta)
A diferencia de los LoRAs aquí solo se PREFIJA la categoría conservando el
nombre completo (versión/arquitectura). Archivos físicos renombrados en
~/ComfyUI/models/checkpoints, /mnt/2tb/comfyui_models/{checkpoints,
diffusion_models} y la subcarpeta hy3dgen/. Mapa de reversión en
~/ComfyUI/models/checkpoints/_ckpt_rename_map.json.
Actualiza todas las refs (ckpt_name/unet_name + defaults + prosa) en los
builders gamedev/vídeo/3D, style presets, pipelines, tests y los workflows
de ComfyUI. Arregla de paso el default roto de comfyui_text_to_3d_oneshot
(apuntaba a v1-5-pruned-emaonly.safetensors inexistente; ahora al real
IMG_v1-5-pruned-emaonly-fp16.safetensors).
No tocados (justificado): repo-paths de HuggingFace en comfyui_install_3d_model
(<repo>/model.fp16.safetensors son rutas de descarga, no nombres de dropdown)
y el mock de stable-diffusion.cpp en test_genconfig_to_sdcpp_args.
Verificado: dropdowns CheckpointLoaderSimple + UNETLoader listan los nombres
con prefijo; 1 generación real con IMG_juggernaut_xl_v11 (node_errors vacío,
pixelart_00003_.png); 327 tests comfyui verdes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ lang: py
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def comfyui_generate_asset_pack_oneshot(pack: list, *, checkpoint: str = \"dreamshaper_8.safetensors\", style: str = \"\", lora: str | None = None, lora_strength: float = 1.0, base_seed: int = 0, size: int | None = None, server: str = \"127.0.0.1:8188\", export_godot: str | None = None, out_dir: str | None = None, wait_timeout: float = 600.0, godot_bin: str | None = None) -> dict"
|
||||
signature: "def comfyui_generate_asset_pack_oneshot(pack: list, *, checkpoint: str = \"IMG_dreamshaper_8.safetensors\", style: str = \"\", lora: str | None = None, lora_strength: float = 1.0, base_seed: int = 0, size: int | None = None, server: str = \"127.0.0.1:8188\", export_godot: str | None = None, out_dir: str | None = None, wait_timeout: float = 600.0, godot_bin: str | None = None) -> dict"
|
||||
description: "One-shot del grupo gamedev-2d: recibe una spec de pack (lista de assets, cada uno con kind + subject) y genera el set 2D ENTERO de un juego compartiendo el MISMO checkpoint, el MISMO LoRA de estilo, un estilo comun (concatenado al subject de cada asset) y una semilla derivada (seed = base_seed + indice), de modo que sprite + iconos + tiles + UI peguen entre si (misma mano, misma paleta, mismo modelo). Despacha cada kind a su builder atomico del registry (item_icon, enemy_creature, prop_object, seamless_tile, ui_hud, particle_texture, ... 26 kinds), encola con comfyui_submit_workflow, espera con comfyui_wait_result, descarga el PNG con comfyui_fetch_output_image y (si export_godot) exporta cada asset al proyecto Godot con comfyui_export_asset_to_godot. Promueve a UNA llamada la composicion repetida 'llamar N builders con el mismo estilo' (issue 0087): el registry no crece inflando builders, crece promoviendo composiciones a pipelines. Un fallo aislado (p.ej. OOM en un asset) NO aborta el resto. Devuelve {ok, pack_dir, checkpoint, style, lora, base_seed, coherence_note, count, generated, failed, assets, error}. Impuro: HTTP a ComfyUI + disco + (export) subprocess."
|
||||
tags: [gamedev-2d, pipelines, comfyui, ml, godot]
|
||||
uses_functions: [comfyui_build_achievement_badge_workflow_py_ml, comfyui_build_card_art_workflow_py_ml, comfyui_build_decal_overlay_workflow_py_ml, comfyui_build_dialogue_box_workflow_py_ml, comfyui_build_emote_workflow_py_ml, comfyui_build_enemy_creature_workflow_py_ml, comfyui_build_foliage_set_workflow_py_ml, comfyui_build_item_icon_workflow_py_ml, comfyui_build_parallax_background_workflow_py_ml, comfyui_build_particle_texture_workflow_py_ml, comfyui_build_portrait_avatar_workflow_py_ml, comfyui_build_projectile_workflow_py_ml, comfyui_build_prop_object_workflow_py_ml, comfyui_build_rune_glyph_workflow_py_ml, comfyui_build_seamless_tile_workflow_py_ml, comfyui_build_skill_tree_node_workflow_py_ml, comfyui_build_splash_art_workflow_py_ml, comfyui_build_status_effect_icon_workflow_py_ml, comfyui_build_structure_workflow_py_ml, comfyui_build_title_lettering_workflow_py_ml, comfyui_build_topdown_sprite_workflow_py_ml, comfyui_build_trap_hazard_workflow_py_ml, comfyui_build_ui_hud_workflow_py_ml, comfyui_build_vehicle_mount_workflow_py_ml, comfyui_build_weather_overlay_workflow_py_ml, comfyui_build_world_map_workflow_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, comfyui_export_asset_to_godot_py_pipelines]
|
||||
@@ -65,7 +65,7 @@ res = comfyui_generate_asset_pack_oneshot(
|
||||
{"kind": "item_icon", "subject": "magic sword"},
|
||||
{"kind": "enemy_creature", "subject": "goblin warrior"},
|
||||
],
|
||||
checkpoint="dreamshaper_8.safetensors",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors",
|
||||
style="dark fantasy, hand-painted", # firma visual compartida
|
||||
base_seed=42, # seeds 42, 43, ...
|
||||
size=512,
|
||||
@@ -73,7 +73,7 @@ res = comfyui_generate_asset_pack_oneshot(
|
||||
)
|
||||
# res["ok"] -> True
|
||||
# res["assets"][0] -> {"kind":"item_icon","seed":42,"prompt_id":"...","path":"/tmp/asset_pack_demo/item_icon_00042_.png", ...}
|
||||
# res["coherence_note"] -> "Set coherente: checkpoint='dreamshaper_8.safetensors', style='dark fantasy, hand-painted', ..."
|
||||
# res["coherence_note"] -> "Set coherente: checkpoint='IMG_dreamshaper_8.safetensors', style='dark fantasy, hand-painted', ..."
|
||||
|
||||
# Con export directo a un proyecto Godot 4 (cada PNG a res://assets/... + .import):
|
||||
res = comfyui_generate_asset_pack_oneshot(
|
||||
@@ -107,7 +107,7 @@ Si ademas quieres llevarlos a Godot sin tocar imports, pasa `export_godot`.
|
||||
"game icon, clean, centered"). Si un item trae su propio `checkpoint`/`style` en
|
||||
los kwargs extra, ESE asset rompe la coherencia a proposito (override explicito).
|
||||
- **VRAM / OOM.** Genera secuencialmente (un asset cada vez), pero cada uno carga el
|
||||
modelo. Con poca VRAM usa SD1.5 (`dreamshaper_8`) + `size=512` y packs pequenos.
|
||||
modelo. Con poca VRAM usa SD1.5 (`IMG_dreamshaper_8`) + `size=512` y packs pequenos.
|
||||
Si un asset peta por OOM, **NO** aborta el pack: ese asset queda `ok=False` con su
|
||||
`error` y el resto continua. Reduce el pack o `size`, no mates procesos. Conviene
|
||||
liberar VRAM antes: `POST http://127.0.0.1:8188/free {"unload_models":true,"free_memory":true}`.
|
||||
|
||||
@@ -217,7 +217,7 @@ def _first_image(outputs: dict) -> dict | None:
|
||||
def comfyui_generate_asset_pack_oneshot(
|
||||
pack: list,
|
||||
*,
|
||||
checkpoint: str = "dreamshaper_8.safetensors",
|
||||
checkpoint: str = "IMG_dreamshaper_8.safetensors",
|
||||
style: str = "",
|
||||
lora: str | None = None,
|
||||
lora_strength: float = 1.0,
|
||||
@@ -390,7 +390,7 @@ if __name__ == "__main__":
|
||||
{"kind": "item_icon", "subject": "magic sword"},
|
||||
{"kind": "enemy_creature", "subject": "goblin warrior"},
|
||||
],
|
||||
checkpoint="dreamshaper_8.safetensors",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors",
|
||||
style="dark fantasy, hand-painted",
|
||||
base_seed=42,
|
||||
size=512,
|
||||
|
||||
@@ -28,13 +28,13 @@ from pipelines.comfyui_generate_asset_pack_oneshot import ( # noqa: E402
|
||||
def test_dispatch_shares_checkpoint_and_seed():
|
||||
wf, subject_eff, godot_kind, seed = _build_item_workflow(
|
||||
{"kind": "item_icon", "subject": "magic sword"},
|
||||
checkpoint="dreamshaper_8.safetensors", style="dark fantasy, hand-painted",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="dark fantasy, hand-painted",
|
||||
lora=None, lora_strength=1.0, base_seed=42, size=512, index=0,
|
||||
)
|
||||
blob = json.dumps(wf)
|
||||
assert godot_kind == "sprite"
|
||||
assert seed == 42 # base_seed(42) + index(0)
|
||||
assert "dreamshaper_8.safetensors" in blob # checkpoint compartido
|
||||
assert "IMG_dreamshaper_8.safetensors" in blob # checkpoint compartido
|
||||
assert "dark fantasy, hand-painted" in subject_eff # style inyectado al subject
|
||||
assert "magic sword" in subject_eff
|
||||
assert "42" in blob # seed en el sampler
|
||||
@@ -43,7 +43,7 @@ def test_dispatch_shares_checkpoint_and_seed():
|
||||
def test_seed_is_base_plus_index():
|
||||
_, _, _, seed = _build_item_workflow(
|
||||
{"kind": "enemy_creature", "subject": "goblin"},
|
||||
checkpoint="dreamshaper_8.safetensors", style="", lora=None,
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="", lora=None,
|
||||
lora_strength=1.0, base_seed=100, size=None, index=3,
|
||||
)
|
||||
assert seed == 103
|
||||
@@ -61,7 +61,7 @@ def test_godot_kind_per_category():
|
||||
for kind, expected in cases.items():
|
||||
_, _, godot_kind, _ = _build_item_workflow(
|
||||
{"kind": kind, "subject": "x"},
|
||||
checkpoint="dreamshaper_8.safetensors", style="", lora=None,
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="", lora=None,
|
||||
lora_strength=1.0, base_seed=0, size=None, index=0,
|
||||
)
|
||||
assert godot_kind == expected, kind
|
||||
@@ -71,13 +71,13 @@ def test_emote_requires_expression():
|
||||
with pytest.raises(ValueError, match="expression"):
|
||||
_build_item_workflow(
|
||||
{"kind": "emote", "subject": "hero"}, # falta 'expression'
|
||||
checkpoint="dreamshaper_8.safetensors", style="", lora=None,
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="", lora=None,
|
||||
lora_strength=1.0, base_seed=0, size=None, index=0,
|
||||
)
|
||||
# con expression sí construye
|
||||
wf, _, godot_kind, _ = _build_item_workflow(
|
||||
{"kind": "emote", "subject": "hero", "expression": "angry"},
|
||||
checkpoint="dreamshaper_8.safetensors", style="", lora=None,
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="", lora=None,
|
||||
lora_strength=1.0, base_seed=0, size=None, index=0,
|
||||
)
|
||||
assert godot_kind == "sprite" and isinstance(wf, dict)
|
||||
@@ -87,7 +87,7 @@ def test_per_item_kwargs_passthrough():
|
||||
# 'tier' es un kwarg propio de achievement_badge -> debe llegar al builder.
|
||||
wf, _, _, _ = _build_item_workflow(
|
||||
{"kind": "achievement_badge", "subject": "first kill", "tier": "platinum"},
|
||||
checkpoint="dreamshaper_8.safetensors", style="", lora=None,
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="", lora=None,
|
||||
lora_strength=1.0, base_seed=0, size=None, index=0,
|
||||
)
|
||||
assert "platinum" in json.dumps(wf)
|
||||
@@ -99,7 +99,7 @@ def test_unknown_kind_fails_without_network():
|
||||
res = comfyui_generate_asset_pack_oneshot(
|
||||
[{"kind": "item_icon", "subject": "ok"},
|
||||
{"kind": "does_not_exist", "subject": "x"}],
|
||||
checkpoint="dreamshaper_8.safetensors",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors",
|
||||
)
|
||||
assert res["ok"] is False
|
||||
assert "no soportado" in res["error"]
|
||||
@@ -142,7 +142,7 @@ def test_full_flow_mocked(monkeypatch, tmp_path):
|
||||
res = comfyui_generate_asset_pack_oneshot(
|
||||
[{"kind": "item_icon", "subject": "magic sword"},
|
||||
{"kind": "enemy_creature", "subject": "goblin warrior"}],
|
||||
checkpoint="dreamshaper_8.safetensors", style="dark fantasy, hand-painted",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="dark fantasy, hand-painted",
|
||||
base_seed=42, size=512, server="http://127.0.0.1:8188",
|
||||
out_dir=str(tmp_path),
|
||||
)
|
||||
@@ -151,8 +151,8 @@ def test_full_flow_mocked(monkeypatch, tmp_path):
|
||||
assert [a["seed"] for a in res["assets"]] == [42, 43]
|
||||
assert all(a["prompt_id"].startswith("pid-") for a in res["assets"])
|
||||
assert all(os.path.isfile(a["path"]) for a in res["assets"])
|
||||
assert "dreamshaper_8.safetensors" in res["coherence_note"]
|
||||
assert res["checkpoint"] == "dreamshaper_8.safetensors"
|
||||
assert "IMG_dreamshaper_8.safetensors" in res["coherence_note"]
|
||||
assert res["checkpoint"] == "IMG_dreamshaper_8.safetensors"
|
||||
|
||||
|
||||
def test_one_asset_fails_others_survive(monkeypatch, tmp_path):
|
||||
|
||||
@@ -5,7 +5,7 @@ lang: py
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def comfyui_generate_character_set_oneshot(character: str, *, style: str = \"game character, full body, clean background\", checkpoint: str = \"dreamshaper_8.safetensors\", base_kind: str = \"enemy_creature\", directions: int = 8, make_directional: bool = True, make_3d: bool = True, directional_model: str = \"sv3d\", elevation: float = 15.0, seed: int = 0, size: int = 512, directional_size: int | None = None, flatten_color: tuple = (255, 255, 255), variant_3d: str = \"mini\", lora: str | None = None, lora_strength: float = 1.0, server: str = \"http://127.0.0.1:8188\", export_godot: str | None = None, out_dir: str | None = None, wait_timeout: float = 600.0, free_vram: bool = True, godot_bin: str | None = None) -> dict"
|
||||
signature: "def comfyui_generate_character_set_oneshot(character: str, *, style: str = \"game character, full body, clean background\", checkpoint: str = \"IMG_dreamshaper_8.safetensors\", base_kind: str = \"enemy_creature\", directions: int = 8, make_directional: bool = True, make_3d: bool = True, directional_model: str = \"sv3d\", elevation: float = 15.0, seed: int = 0, size: int = 512, directional_size: int | None = None, flatten_color: tuple = (255, 255, 255), variant_3d: str = \"mini\", lora: str | None = None, lora_strength: float = 1.0, server: str = \"http://127.0.0.1:8188\", export_godot: str | None = None, out_dir: str | None = None, wait_timeout: float = 600.0, free_vram: bool = True, godot_bin: str | None = None) -> dict"
|
||||
description: "Culminacion del grupo gamedev-2d: genera el set COMPLETO y coherente de UN personaje de juego de un solo tiro — (1) imagen base 2D recortada a alpha, (2) sprite direccional N-way (vistas 3D consistentes SV3D/Zero123) y (3) malla 3D .glb (Hunyuan3D-2). La CLAVE es la coherencia cross-frontera: la vista direccional y la malla 3D parten de la MISMA imagen base 2D aplanada, no de tres generaciones independientes, asi que las tres representaciones son del MISMO personaje con el mismo estilo (no tres personajes distintos). Promueve a UNA llamada la secuencia que hoy exige 4 funciones a mano (issue 0087). Compone: un builder de personaje (enemy_creature/portrait_avatar/topdown_sprite) + comfyui_flatten_alpha_on_color + comfyui_image_to_3d_oneshot + comfyui_build_directional_sprite_workflow + submit/wait/fetch + comfyui_export_asset_to_godot. Secuencial liberando VRAM (POST /free) entre los pasos pesados para caber en 8 GB; el 3D va antes que el direccional (SV3D es el de mayor pico). Un fallo aislado (p.ej. OOM en el 3D) NO aborta el resto: deja el set PARCIAL. Devuelve {ok, character, style, checkpoint, base_kind, seed, coherence_note, base_image, base_flat, base_prompt_id, directional, mesh, exported, steps, error}. Impuro: HTTP a ComfyUI + disco + (export) subprocess."
|
||||
tags: [gamedev-2d, pipelines, comfyui, ml, godot]
|
||||
uses_functions: [comfyui_build_enemy_creature_workflow_py_ml, comfyui_build_portrait_avatar_workflow_py_ml, comfyui_build_topdown_sprite_workflow_py_ml, comfyui_build_directional_sprite_workflow_py_ml, comfyui_flatten_alpha_on_color_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, comfyui_image_to_3d_oneshot_py_pipelines, comfyui_export_asset_to_godot_py_pipelines]
|
||||
|
||||
@@ -180,7 +180,7 @@ def comfyui_generate_character_set_oneshot(
|
||||
character: str,
|
||||
*,
|
||||
style: str = "game character, full body, clean background",
|
||||
checkpoint: str = "dreamshaper_8.safetensors",
|
||||
checkpoint: str = "IMG_dreamshaper_8.safetensors",
|
||||
base_kind: str = "enemy_creature",
|
||||
directions: int = 8,
|
||||
make_directional: bool = True,
|
||||
|
||||
@@ -54,11 +54,11 @@ def test_nothing_to_generate_fails():
|
||||
def test_base_builder_introspection_injects_coherence():
|
||||
wf = _build_base_workflow(
|
||||
"enemy_creature", "armored paladin",
|
||||
checkpoint="dreamshaper_8.safetensors", style="dark fantasy",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors", style="dark fantasy",
|
||||
size=512, seed=77, lora=None, lora_strength=1.0,
|
||||
)
|
||||
blob = json.dumps(wf)
|
||||
assert "dreamshaper_8.safetensors" in blob # checkpoint compartido
|
||||
assert "IMG_dreamshaper_8.safetensors" in blob # checkpoint compartido
|
||||
assert "armored paladin" in blob # personaje
|
||||
assert "77" in blob # seed en el sampler
|
||||
# transparent=True -> el builder inyecta el nodo Rembg (base recortada a alpha)
|
||||
|
||||
@@ -62,7 +62,7 @@ from pipelines.comfyui_generate_mixed_oneshot import comfyui_generate_mixed_ones
|
||||
res = comfyui_generate_mixed_oneshot(
|
||||
"txt2img",
|
||||
"a heroic knight in 3d render style, dramatic lighting",
|
||||
checkpoint="dreamshaper_8.safetensors",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors",
|
||||
capabilities={
|
||||
"loras": [
|
||||
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||
|
||||
@@ -207,7 +207,7 @@ if __name__ == "__main__":
|
||||
res = comfyui_generate_mixed_oneshot(
|
||||
"txt2img",
|
||||
"a heroic knight in 3d render style, dramatic lighting",
|
||||
checkpoint="dreamshaper_8.safetensors",
|
||||
checkpoint="IMG_dreamshaper_8.safetensors",
|
||||
capabilities={
|
||||
"loras": [
|
||||
{"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
|
||||
|
||||
@@ -127,8 +127,8 @@ este pipeline lo recoge sin tocarse.
|
||||
invalido devuelve `ok=False` con error claro y `prompt_id == ""`. La parte pura es
|
||||
invocable sola con `styled_asset_build_only(...)` para inspeccionar el grafo y el post sin
|
||||
generar.
|
||||
- **VRAM / OOM (RTX 3070 8 GB).** Los presets nuevos usan SD1.5 (dreamshaper_8) a 512 y caben
|
||||
holgados; pixel-art-retro usa SDXL (juggernaut_xl_v11) a 768 y pica mas. Con modelos ya
|
||||
- **VRAM / OOM (RTX 3070 8 GB).** Los presets nuevos usan SD1.5 (IMG_dreamshaper_8) a 512 y caben
|
||||
holgados; pixel-art-retro usa SDXL (IMG_juggernaut_xl_v11) a 768 y pica mas. Con modelos ya
|
||||
cargados de otra tarea, pasa `free_vram=True` (hace `POST /free` antes de generar) o limpia
|
||||
tu mismo (`POST http://127.0.0.1:8188/free {"unload_models":true,"free_memory":true}`). Si
|
||||
hay OOM, baja la resolucion del preset o el `size` del builder via `builder_extra`; NO se
|
||||
|
||||
@@ -55,7 +55,7 @@ def test_build_only_preset_drives_workflow():
|
||||
built = styled_asset_build_only("item_icon", "knight character", "gameboy", seed=7)
|
||||
blob = json.dumps(built["workflow"])
|
||||
# checkpoint del preset gameboy (SD1.5)
|
||||
assert "dreamshaper_8.safetensors" in blob
|
||||
assert "IMG_dreamshaper_8.safetensors" in blob
|
||||
# el subject combinó el sufijo del estilo gameboy
|
||||
assert "8-bit" in built["applied"]["subject"]
|
||||
# el style del preset SUSTITUYE el style categórico del builder
|
||||
|
||||
@@ -89,5 +89,5 @@ variante con `recipe_patch`, compara `judge.score`, y si la variante gana llama
|
||||
cuanto los outputs están listos.
|
||||
- **Juez caído ≠ fallo fatal**: si el panel entero falla, la imagen ya está en disco; el resultado
|
||||
vuelve con `ok=True`, `judge=None` y `error` anotado.
|
||||
- **OOM en 8GB**: si el server va corto de VRAM, usa una skill SD1.5 (`dreamshaper_8`) a resolución
|
||||
- **OOM en 8GB**: si el server va corto de VRAM, usa una skill SD1.5 (`IMG_dreamshaper_8`) a resolución
|
||||
modesta; el error de OOM se propaga en `{ok:False, error}` sin reiniciar el server.
|
||||
|
||||
@@ -38,9 +38,9 @@ from ml.comfyui_wait_result import comfyui_wait_result
|
||||
|
||||
# variant -> nombre del checkpoint que espera ImageOnlyCheckpointLoader.
|
||||
_VARIANT_CKPT = {
|
||||
"mini": "hunyuan3d-dit-v2-mini.safetensors",
|
||||
"standard": "hunyuan3d-dit-v2-0.safetensors",
|
||||
"mv": "hunyuan3d-dit-v2-mv.safetensors",
|
||||
"mini": "3D_hunyuan3d-dit-v2-mini.safetensors",
|
||||
"standard": "3D_hunyuan3d-dit-v2-0.safetensors",
|
||||
"mv": "3D_hunyuan3d-dit-v2-mv.safetensors",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ from pipelines.comfyui_replicate_civitai_oneshot import comfyui_replicate_civita
|
||||
out = comfyui_replicate_civitai_oneshot("https://civitai.com/images/23526611")
|
||||
print(out["ok"], out["replica_image_path"])
|
||||
print(out["source"]["family"], out["source"]["sampler_name"]) # flux euler
|
||||
print(out["missing_models"]) # [{'kind':'checkpoint','name':'FLUX','substituted_with':'juggernaut_xl_v11.safetensors',...}]
|
||||
print(out["missing_models"]) # [{'kind':'checkpoint','name':'FLUX','substituted_with':'IMG_juggernaut_xl_v11.safetensors',...}]
|
||||
print(out["judge"]["verdict"], round(out["judge"]["score"], 2)) # bad 4.74 (parecido aproximado sin el modelo exacto)
|
||||
```
|
||||
|
||||
|
||||
@@ -30,18 +30,18 @@ def test_classify_input_image_modelversion_workflow_error():
|
||||
|
||||
|
||||
def test_pick_checkpoint_familia_y_exacto():
|
||||
installed = ["dreamshaper_8.safetensors", "juggernaut_xl_v11.safetensors",
|
||||
"v1-5-pruned-emaonly-fp16.safetensors", "svd.safetensors",
|
||||
"hunyuan3d-dit-v2-mini.safetensors"]
|
||||
installed = ["IMG_dreamshaper_8.safetensors", "IMG_juggernaut_xl_v11.safetensors",
|
||||
"IMG_v1-5-pruned-emaonly-fp16.safetensors", "VIDEO_svd.safetensors",
|
||||
"3D_hunyuan3d-dit-v2-mini.safetensors"]
|
||||
# familia sdxl -> elige el que tiene 'xl'
|
||||
ck, exact = _pick_checkpoint(installed, "sdxl", "algun_modelo_no_instalado")
|
||||
assert ck == "juggernaut_xl_v11.safetensors" and exact is False
|
||||
assert ck == "IMG_juggernaut_xl_v11.safetensors" and exact is False
|
||||
# familia sd15 -> evita los xl y los de video/3d
|
||||
ck, exact = _pick_checkpoint(installed, "sd15", "otro")
|
||||
assert "xl" not in ck.lower() and "svd" not in ck and exact is False
|
||||
# hint exacto instalado -> exact True
|
||||
ck, exact = _pick_checkpoint(installed, "sd15", "dreamshaper_8")
|
||||
assert ck == "dreamshaper_8.safetensors" and exact is True
|
||||
ck, exact = _pick_checkpoint(installed, "sd15", "IMG_dreamshaper_8")
|
||||
assert ck == "IMG_dreamshaper_8.safetensors" and exact is True
|
||||
|
||||
|
||||
def test_find_installed_match_normalizado():
|
||||
|
||||
@@ -5,7 +5,7 @@ lang: py
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def comfyui_text_to_3d_oneshot(prompt: str, *, server: str = \"127.0.0.1:8188\", ckpt_name: str = \"v1-5-pruned-emaonly.safetensors\", negative: str = \"\", textured: bool = False, variant: str = \"mini\", dest: str | None = None, image_wait_timeout: float = 300.0, wait_timeout: float = 600.0, **gen) -> dict"
|
||||
signature: "def comfyui_text_to_3d_oneshot(prompt: str, *, server: str = \"127.0.0.1:8188\", ckpt_name: str = \"IMG_v1-5-pruned-emaonly-fp16.safetensors\", negative: str = \"\", textured: bool = False, variant: str = \"mini\", dest: str | None = None, image_wait_timeout: float = 300.0, wait_timeout: float = 600.0, **gen) -> dict"
|
||||
description: "Pipeline prompt de texto -> malla 3D GLB en una sola llamada. Genera una imagen desde texto con Stable Diffusion (txt2img), la sube al input/ del servidor y reconstruye una malla 3D desde ella (malla nativa Hunyuan3D-2 o, con textured=True, malla texturizada PBR multi-vista). Compone comfyui_build_txt2img_workflow + submit + wait + fetch_output_image + comfyui_build_image_to_3d_workflow (o comfyui_build_textured_3d_multiview_workflow) + submit + wait + comfyui_fetch_output_mesh. Reutiliza el helper de upload del pipeline hermano comfyui_image_to_3d_oneshot. Promocion de secuencia texto->imagen->3D (issue 0087). Impuro: HTTP + disco."
|
||||
tags: [comfyui, img-to-3d, pipelines, ml, stable-diffusion, hunyuan3d]
|
||||
uses_functions:
|
||||
@@ -28,7 +28,7 @@ params:
|
||||
- name: server
|
||||
desc: "host:port del servidor ComfyUI (sin esquema). keyword-only."
|
||||
- name: ckpt_name
|
||||
desc: "Checkpoint Stable Diffusion para el txt2img (default SD1.5 v1-5-pruned-emaonly). keyword-only."
|
||||
desc: "Checkpoint Stable Diffusion para el txt2img (default SD1.5 IMG_v1-5-pruned-emaonly-fp16). keyword-only."
|
||||
- name: negative
|
||||
desc: "Prompt negativo del txt2img. keyword-only."
|
||||
- name: textured
|
||||
|
||||
@@ -47,9 +47,9 @@ from pipelines.comfyui_image_to_3d_oneshot import _upload_image
|
||||
|
||||
# variant -> nombre del checkpoint Hunyuan3D-2 para el paso 3D no texturizado.
|
||||
_VARIANT_CKPT = {
|
||||
"mini": "hunyuan3d-dit-v2-mini.safetensors",
|
||||
"standard": "hunyuan3d-dit-v2-0.safetensors",
|
||||
"mv": "hunyuan3d-dit-v2-mv.safetensors",
|
||||
"mini": "3D_hunyuan3d-dit-v2-mini.safetensors",
|
||||
"standard": "3D_hunyuan3d-dit-v2-0.safetensors",
|
||||
"mv": "3D_hunyuan3d-dit-v2-mv.safetensors",
|
||||
}
|
||||
|
||||
# Claves de **gen que reenviamos a comfyui_build_txt2img_workflow; cualquier otra
|
||||
@@ -88,7 +88,7 @@ def comfyui_text_to_3d_oneshot(
|
||||
prompt: str,
|
||||
*,
|
||||
server: str = "127.0.0.1:8188",
|
||||
ckpt_name: str = "v1-5-pruned-emaonly.safetensors",
|
||||
ckpt_name: str = "IMG_v1-5-pruned-emaonly-fp16.safetensors",
|
||||
negative: str = "",
|
||||
textured: bool = False,
|
||||
variant: str = "mini",
|
||||
|
||||
@@ -5,7 +5,7 @@ lang: py
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def comfyui_txt2img_oneshot(prompt: str, *, ckpt: str = \"dreamshaper_8.safetensors\", negative: str = \"\", server: str = \"127.0.0.1:8188\", dest: str | None = None, wait_timeout: float = 300.0, **gen) -> dict"
|
||||
signature: "def comfyui_txt2img_oneshot(prompt: str, *, ckpt: str = \"IMG_dreamshaper_8.safetensors\", negative: str = \"\", server: str = \"127.0.0.1:8188\", dest: str | None = None, wait_timeout: float = 300.0, **gen) -> dict"
|
||||
description: "Pipeline prompt de texto -> PNG en disco en una sola llamada. Construye el workflow txt2img de Stable Diffusion, lo encola en ComfyUI, espera y descarga la imagen. Compone comfyui_build_txt2img_workflow + comfyui_submit_workflow + comfyui_wait_result + comfyui_fetch_output_image. Promocion de secuencia (issue 0087). Impuro: HTTP + disco."
|
||||
tags: [comfyui, pipelines, txt2img, stable-diffusion, launcher]
|
||||
uses_functions: [comfyui_build_txt2img_workflow_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml]
|
||||
@@ -18,7 +18,7 @@ params:
|
||||
- name: prompt
|
||||
desc: "Prompt positivo (lo que se quiere ver en la imagen)."
|
||||
- name: ckpt
|
||||
desc: "Checkpoint Stable Diffusion tal como lo ve el servidor (CheckpointLoaderSimple). Por defecto 'dreamshaper_8.safetensors'. keyword-only."
|
||||
desc: "Checkpoint Stable Diffusion tal como lo ve el servidor (CheckpointLoaderSimple). Por defecto 'IMG_dreamshaper_8.safetensors'. keyword-only."
|
||||
- name: negative
|
||||
desc: "Prompt negativo. Por defecto ''. keyword-only."
|
||||
- name: server
|
||||
@@ -73,7 +73,7 @@ este pipeline ejecuta el camino básico end-to-end).
|
||||
- Impuro: requiere el **servidor ComfyUI vivo** en `server` (default
|
||||
`127.0.0.1:8188`). Si está caído, falla en el paso submit con el error de conexión.
|
||||
- `ckpt` debe existir en el servidor (CheckpointLoaderSimple). Default
|
||||
`dreamshaper_8.safetensors`; cámbialo si usas SDXL u otro.
|
||||
`IMG_dreamshaper_8.safetensors`; cámbialo si usas SDXL u otro.
|
||||
- `dest` es un **directorio** (se crea si no existe), no un nombre de archivo: el
|
||||
PNG conserva el nombre que le da ComfyUI (`<filename_prefix>_NNNNN_.png`).
|
||||
- `wait_timeout` por defecto 300 s. Subir resolución/steps puede requerir más; si
|
||||
|
||||
@@ -31,7 +31,7 @@ from ml.comfyui_wait_result import comfyui_wait_result
|
||||
def comfyui_txt2img_oneshot(
|
||||
prompt: str,
|
||||
*,
|
||||
ckpt: str = "dreamshaper_8.safetensors",
|
||||
ckpt: str = "IMG_dreamshaper_8.safetensors",
|
||||
negative: str = "",
|
||||
server: str = "127.0.0.1:8188",
|
||||
dest: str | None = None,
|
||||
@@ -43,7 +43,7 @@ def comfyui_txt2img_oneshot(
|
||||
Args:
|
||||
prompt: prompt positivo (lo que se quiere ver en la imagen).
|
||||
ckpt: checkpoint Stable Diffusion tal como lo ve el servidor
|
||||
(CheckpointLoaderSimple). Por defecto "dreamshaper_8.safetensors".
|
||||
(CheckpointLoaderSimple). Por defecto "IMG_dreamshaper_8.safetensors".
|
||||
keyword-only.
|
||||
negative: prompt negativo. Por defecto "". keyword-only.
|
||||
server: host:port del servidor ComfyUI (sin esquema). keyword-only.
|
||||
|
||||
Reference in New Issue
Block a user