chore: auto-commit (14 archivos)
- docs/capabilities/comfyui.md - python/functions/ml/comfyui_build_image_to_3d_workflow.md - python/functions/ml/comfyui_build_image_to_3d_workflow.py - python/functions/ml/tests/test_comfyui_build_image_to_3d_workflow.py - python/functions/ml/comfyui_build_facedetailer_workflow.md - python/functions/ml/comfyui_build_facedetailer_workflow.py - python/functions/ml/comfyui_build_hires_fix_workflow.md - python/functions/ml/comfyui_build_hires_fix_workflow.py - python/functions/ml/tests/test_comfyui_build_facedetailer_workflow.py - python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""Tests de comfyui_build_facedetailer_workflow (builder puro, sin red)."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from ml.comfyui_build_facedetailer_workflow import comfyui_build_facedetailer_workflow # noqa: E402
|
||||
from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow # noqa: E402
|
||||
|
||||
|
||||
def test_image_mode_builds_detailer_chain():
|
||||
wf = comfyui_build_facedetailer_workflow(
|
||||
"portrait_00001_.png",
|
||||
ckpt_name="dreamshaper_8.safetensors",
|
||||
positive="detailed face",
|
||||
seed=42,
|
||||
)
|
||||
# Detector + FaceDetailer + SaveImage presentes.
|
||||
assert wf["fd_det"]["class_type"] == "UltralyticsDetectorProvider"
|
||||
assert wf["fd_face"]["class_type"] == "FaceDetailer"
|
||||
assert wf["fd_save"]["class_type"] == "SaveImage"
|
||||
# La imagen viene del LoadImage propio del modo str.
|
||||
assert wf["fd_load"]["class_type"] == "LoadImage"
|
||||
assert wf["fd_face"]["inputs"]["image"] == ["fd_load", 0]
|
||||
# FaceDetailer conecta el bbox_detector y la conditioning.
|
||||
assert wf["fd_face"]["inputs"]["bbox_detector"] == ["fd_det", 0]
|
||||
assert wf["fd_face"]["inputs"]["positive"] == ["fd_pos", 0]
|
||||
assert wf["fd_face"]["inputs"]["seed"] == 42
|
||||
|
||||
|
||||
def test_workflow_mode_reuses_base_nodes():
|
||||
base = comfyui_build_txt2img_workflow(
|
||||
ckpt_name="dreamshaper_8.safetensors",
|
||||
positive="portrait of a woman",
|
||||
seed=7,
|
||||
)
|
||||
wf = comfyui_build_facedetailer_workflow(
|
||||
base,
|
||||
ckpt_name="dreamshaper_8.safetensors",
|
||||
positive="detailed face",
|
||||
denoise=0.45,
|
||||
)
|
||||
# Los nodos del base se conservan.
|
||||
assert wf["4"]["class_type"] == "CheckpointLoaderSimple"
|
||||
assert wf["8"]["class_type"] == "VAEDecode"
|
||||
# La imagen del detailer viene del VAEDecode del base.
|
||||
assert wf["fd_face"]["inputs"]["image"] == ["8", 0]
|
||||
# Reutiliza el checkpoint del base (model/clip/vae del nodo "4").
|
||||
assert wf["fd_face"]["inputs"]["model"] == ["4", 0]
|
||||
assert wf["fd_face"]["inputs"]["vae"] == ["4", 2]
|
||||
assert wf["fd_face"]["inputs"]["denoise"] == 0.45
|
||||
|
||||
|
||||
def test_normalizes_short_bbox_model():
|
||||
wf = comfyui_build_facedetailer_workflow(
|
||||
"x.png", ckpt_name="dreamshaper_8.safetensors", positive="face",
|
||||
bbox_model="face_yolov8m.pt",
|
||||
)
|
||||
assert wf["fd_det"]["inputs"]["model_name"] == "bbox/face_yolov8m.pt"
|
||||
# Un nombre ya prefijado se respeta.
|
||||
wf2 = comfyui_build_facedetailer_workflow(
|
||||
"x.png", ckpt_name="dreamshaper_8.safetensors", positive="face",
|
||||
bbox_model="bbox/face_yolov8m.pt",
|
||||
)
|
||||
assert wf2["fd_det"]["inputs"]["model_name"] == "bbox/face_yolov8m.pt"
|
||||
|
||||
|
||||
def test_dict_without_vaedecode_raises():
|
||||
with pytest.raises(ValueError):
|
||||
comfyui_build_facedetailer_workflow(
|
||||
{"1": {"class_type": "LoadImage", "inputs": {"image": "x.png"}}},
|
||||
ckpt_name="dreamshaper_8.safetensors",
|
||||
positive="face",
|
||||
)
|
||||
|
||||
|
||||
def test_invalid_base_type_raises():
|
||||
with pytest.raises(ValueError):
|
||||
comfyui_build_facedetailer_workflow(
|
||||
123, ckpt_name="dreamshaper_8.safetensors", positive="face",
|
||||
)
|
||||
@@ -0,0 +1,50 @@
|
||||
"""Tests de comfyui_build_hires_fix_workflow (builder puro, sin red)."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from ml.comfyui_build_hires_fix_workflow import comfyui_build_hires_fix_workflow # noqa: E402
|
||||
|
||||
|
||||
def test_base_ksampler_and_ultimate_upscale_present():
|
||||
wf = comfyui_build_hires_fix_workflow(
|
||||
ckpt_name="dreamshaper_8.safetensors",
|
||||
positive="a fox",
|
||||
seed=42,
|
||||
)
|
||||
# Pasada base = KSampler; pasada de detalle = UltimateSDUpscale.
|
||||
assert wf["3"]["class_type"] == "KSampler"
|
||||
assert wf["12"]["class_type"] == "UltimateSDUpscale"
|
||||
assert wf["9"]["class_type"] == "SaveImage"
|
||||
# El SaveImage cuelga del UltimateSDUpscale (la imagen final).
|
||||
assert wf["9"]["inputs"]["images"] == ["12", 0]
|
||||
|
||||
|
||||
def test_second_pass_denoise_is_partial():
|
||||
wf = comfyui_build_hires_fix_workflow(
|
||||
ckpt_name="dreamshaper_8.safetensors", positive="x", denoise=0.4,
|
||||
)
|
||||
# La base re-genera entera (denoise=1.0); la 2a pasada solo anade detalle (<1).
|
||||
assert wf["3"]["inputs"]["denoise"] == 1.0
|
||||
assert wf["12"]["inputs"]["denoise"] == 0.4
|
||||
assert wf["12"]["inputs"]["denoise"] < 1.0
|
||||
|
||||
|
||||
def test_first_pass_dims_reflected():
|
||||
wf = comfyui_build_hires_fix_workflow(
|
||||
ckpt_name="dreamshaper_8.safetensors", positive="x", first_pass=(640, 960),
|
||||
)
|
||||
assert wf["5"]["inputs"]["width"] == 640
|
||||
assert wf["5"]["inputs"]["height"] == 960
|
||||
|
||||
|
||||
def test_upscale_model_wired():
|
||||
wf = comfyui_build_hires_fix_workflow(
|
||||
ckpt_name="dreamshaper_8.safetensors", positive="x",
|
||||
upscale_model="4x_foolhardy_Remacri.pth",
|
||||
)
|
||||
assert wf["11"]["class_type"] == "UpscaleModelLoader"
|
||||
assert wf["11"]["inputs"]["model_name"] == "4x_foolhardy_Remacri.pth"
|
||||
assert wf["12"]["inputs"]["upscale_model"] == ["11", 0]
|
||||
@@ -40,3 +40,19 @@ def test_imagen_checkpoint_y_salida_glb():
|
||||
assert node_by_ct(wf, "KSampler")["inputs"]["seed"] == 42
|
||||
# SaveGLB es el nodo de salida: produce la malla .glb.
|
||||
assert "SaveGLB" in class_types(wf)
|
||||
|
||||
|
||||
def test_default_conserva_voxeltomeshbasic():
|
||||
# Retro-compatibilidad: sin watertight el nodo "8" es VoxelToMeshBasic.
|
||||
wf = comfyui_build_image_to_3d_workflow("obj.png")
|
||||
assert wf["8"]["class_type"] == "VoxelToMeshBasic"
|
||||
assert "algorithm" not in wf["8"]["inputs"]
|
||||
|
||||
|
||||
def test_watertight_usa_voxeltomesh_surface_net():
|
||||
wf = comfyui_build_image_to_3d_workflow("obj.png", watertight=True)
|
||||
assert wf["8"]["class_type"] == "VoxelToMesh"
|
||||
assert wf["8"]["inputs"]["algorithm"] == "surface net"
|
||||
assert wf["8"]["inputs"]["voxel"] == ["7", 0]
|
||||
# El resto de la cadena no cambia: SaveGLB sigue colgando del nodo "8".
|
||||
assert wf["9"]["inputs"]["mesh"] == ["8", 0]
|
||||
|
||||
Reference in New Issue
Block a user