diff --git a/python/functions/ml/comfyui_build_controlnet_workflow.md b/python/functions/ml/comfyui_build_controlnet_workflow.md index 416b3125..1cbf8b7d 100644 --- a/python/functions/ml/comfyui_build_controlnet_workflow.md +++ b/python/functions/ml/comfyui_build_controlnet_workflow.md @@ -39,7 +39,7 @@ params: desc: "Alto del latente/imagen en px (multiplo de 8). keyword-only." output: "dict en API format con node_ids como claves (CheckpointLoaderSimple '4', EmptyLatentImage '5', LoadImage '10', ControlNetLoader '12', CLIPTextEncode '6'/'7', ControlNetApply '13', KSampler '3', VAEDecode '8', SaveImage '9'). Listo para comfyui_submit_workflow." tested: true -tests: ["usa ControlNetLoader+ControlNetApply", "control_image, modelo cn y strength reflejados"] +tests: ["usa ControlNetLoader+ControlNetApply", "control_image, modelo cn y strength reflejados", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_controlnet_workflow.py" file_path: "python/functions/ml/comfyui_build_controlnet_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_facedetailer_workflow.md b/python/functions/ml/comfyui_build_facedetailer_workflow.md index f9f1b3bf..b614dd47 100644 --- a/python/functions/ml/comfyui_build_facedetailer_workflow.md +++ b/python/functions/ml/comfyui_build_facedetailer_workflow.md @@ -47,7 +47,7 @@ params: desc: "Prefijo del PNG final que escribe SaveImage. keyword-only." output: "dict en API format listo para comfyui_submit_workflow. En modo dict contiene los nodos del workflow base mas los del detailer (node_ids prefijados 'fd_' para no colisionar); el SaveImage 'fd_save' produce la imagen con las caras regeneradas." tested: true -tests: ["modo imagen monta UltralyticsDetectorProvider + FaceDetailer + SaveImage", "modo workflow reutiliza VAEDecode y CheckpointLoaderSimple del base y conserva sus nodos", "normaliza bbox_model corto a prefijo bbox/", "dict sin VAEDecode lanza ValueError"] +tests: ["modo imagen monta UltralyticsDetectorProvider + FaceDetailer + SaveImage", "modo workflow reutiliza VAEDecode y CheckpointLoaderSimple del base y conserva sus nodos", "normaliza bbox_model corto a prefijo bbox/", "dict sin VAEDecode lanza ValueError", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_facedetailer_workflow.py" file_path: "python/functions/ml/comfyui_build_facedetailer_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_hires_fix_workflow.md b/python/functions/ml/comfyui_build_hires_fix_workflow.md index 9dc4853b..af2d5f34 100644 --- a/python/functions/ml/comfyui_build_hires_fix_workflow.md +++ b/python/functions/ml/comfyui_build_hires_fix_workflow.md @@ -47,7 +47,7 @@ params: desc: "Prefijo del PNG final que escribe SaveImage. keyword-only." output: "dict en API format listo para comfyui_submit_workflow. node_ids: '4' CheckpointLoaderSimple, '5' EmptyLatentImage, '6'/'7' CLIPTextEncode, '3' KSampler (base), '8' VAEDecode, '11' UpscaleModelLoader, '12' UltimateSDUpscale, '9' SaveImage." tested: true -tests: ["cadena base (KSampler) + UltimateSDUpscale + SaveImage", "denoise de la 2a pasada <1 (re-difusion parcial)", "first_pass refleja width/height en EmptyLatentImage", "upscale_model llega a UpscaleModelLoader"] +tests: ["cadena base (KSampler) + UltimateSDUpscale + SaveImage", "denoise de la 2a pasada <1 (re-difusion parcial)", "first_pass refleja width/height en EmptyLatentImage", "upscale_model llega a UpscaleModelLoader", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py" file_path: "python/functions/ml/comfyui_build_hires_fix_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_image_to_3d_workflow.md b/python/functions/ml/comfyui_build_image_to_3d_workflow.md index 1340347d..8026e42e 100644 --- a/python/functions/ml/comfyui_build_image_to_3d_workflow.md +++ b/python/functions/ml/comfyui_build_image_to_3d_workflow.md @@ -43,7 +43,7 @@ params: desc: "Si False (default, retro-compatible) el nodo '8' es VoxelToMeshBasic (malla NO estanca). Si True usa VoxelToMesh con algorithm='surface net', que produce una malla estanca/manifold de raiz sin post-proceso. keyword-only." output: "dict en API format con node_ids '1'..'9' como claves; cada valor tiene class_type + inputs. Listo para comfyui_submit_workflow. El nodo '9' (SaveGLB) produce el archivo .glb en el output del servidor. El nodo '8' es VoxelToMeshBasic (watertight=False) o VoxelToMesh surface-net (watertight=True)." tested: true -tests: ["cadena de 9 nodos Hunyuan3D-2 nativos", "imagen, checkpoint, seed reflejados y SaveGLB presente", "watertight=True usa VoxelToMesh surface-net; default conserva VoxelToMeshBasic"] +tests: ["cadena de 9 nodos Hunyuan3D-2 nativos", "imagen, checkpoint, seed reflejados y SaveGLB presente", "watertight=True usa VoxelToMesh surface-net; default conserva VoxelToMeshBasic", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_image_to_3d_workflow.py" file_path: "python/functions/ml/comfyui_build_image_to_3d_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_img2img_workflow.md b/python/functions/ml/comfyui_build_img2img_workflow.md index 78a724f3..cb834e63 100644 --- a/python/functions/ml/comfyui_build_img2img_workflow.md +++ b/python/functions/ml/comfyui_build_img2img_workflow.md @@ -37,7 +37,7 @@ params: desc: "Scheduler del sampler (ej. 'normal', 'karras'). keyword-only." output: "dict en API format con node_ids como claves (CheckpointLoaderSimple '4', LoadImage '10', VAEEncode '11', CLIPTextEncode '6'/'7', KSampler '3', VAEDecode '8', SaveImage '9'). Listo para comfyui_submit_workflow." tested: true -tests: ["usa VAEEncode/LoadImage y no EmptyLatentImage", "denoise e init_image reflejados"] +tests: ["usa VAEEncode/LoadImage y no EmptyLatentImage", "denoise e init_image reflejados", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_img2img_workflow.py" file_path: "python/functions/ml/comfyui_build_img2img_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_inpaint_workflow.md b/python/functions/ml/comfyui_build_inpaint_workflow.md index effc3b94..b62c60bb 100644 --- a/python/functions/ml/comfyui_build_inpaint_workflow.md +++ b/python/functions/ml/comfyui_build_inpaint_workflow.md @@ -39,7 +39,7 @@ params: desc: "Scheduler del sampler (ej. 'normal', 'karras'). keyword-only." output: "dict en API format con node_ids como claves (CheckpointLoaderSimple '4', LoadImage '10', LoadImageMask '12', VAEEncodeForInpaint '11', CLIPTextEncode '6'/'7', KSampler '3', VAEDecode '8', SaveImage '9'). Listo para comfyui_submit_workflow." tested: true -tests: ["usa LoadImageMask+VAEEncodeForInpaint", "imagen base, mascara, seed y denoise reflejados"] +tests: ["usa LoadImageMask+VAEEncodeForInpaint", "imagen base, mascara, seed y denoise reflejados", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_inpaint_workflow.py" file_path: "python/functions/ml/comfyui_build_inpaint_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_sdxl_refiner_workflow.md b/python/functions/ml/comfyui_build_sdxl_refiner_workflow.md index 7886d916..5460b19b 100644 --- a/python/functions/ml/comfyui_build_sdxl_refiner_workflow.md +++ b/python/functions/ml/comfyui_build_sdxl_refiner_workflow.md @@ -37,7 +37,7 @@ params: desc: "Alto del latente/imagen en px (SDXL nativo 1024). keyword-only." output: "dict en API format con node_ids como claves (CheckpointLoaderSimple base '4' y refiner '14', EmptyLatentImage '5', CLIPTextEncode base '6'/'7' y refiner '16'/'17', KSamplerAdvanced base '3' y refiner '15', VAEDecode '8', SaveImage '9'). Listo para comfyui_submit_workflow." tested: true -tests: ["dos KSamplerAdvanced encadenados", "base emite ruido sobrante y refiner lo recoge (start/end_at_step compartidos)"] +tests: ["dos KSamplerAdvanced encadenados", "base emite ruido sobrante y refiner lo recoge (start/end_at_step compartidos)", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_sdxl_refiner_workflow.py" file_path: "python/functions/ml/comfyui_build_sdxl_refiner_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_textured_3d_multiview_workflow.md b/python/functions/ml/comfyui_build_textured_3d_multiview_workflow.md index a18ae42c..feaeb29d 100644 --- a/python/functions/ml/comfyui_build_textured_3d_multiview_workflow.md +++ b/python/functions/ml/comfyui_build_textured_3d_multiview_workflow.md @@ -29,7 +29,7 @@ params: desc: "Modelo de upscale ESRGAN en upscale_models/ para mejorar las vistas antes del bake (factor dominante de cobertura). Cadena vacia desactiva el upscale. keyword-only." output: "dict en API format listo para comfyui_submit_workflow. node_ids '1'..'19'; los nodos de upscale ('13'..'15') solo presentes si upscale_model esta activo. El SaveGLB-equivalente Hy3DExportMesh produce un .glb texturizado en output/3D/." tested: true -tests: ["estructura completa shape+paint+upscale (18 class_types)", "params imagen/ckpt/octree/max_faces reflejados", "6 vistas configuran 6 azimuths/elevations", "4 vistas configuran 4 azimuths", "sin upscale omite nodos Remacri y el bake toma del sample", "views invalido lanza ValueError"] +tests: ["estructura completa shape+paint+upscale (18 class_types)", "params imagen/ckpt/octree/max_faces reflejados", "6 vistas configuran 6 azimuths/elevations", "4 vistas configuran 4 azimuths", "sin upscale omite nodos Remacri y el bake toma del sample", "views invalido lanza ValueError", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_textured_3d_multiview_workflow.py" file_path: "python/functions/ml/comfyui_build_textured_3d_multiview_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_txt2img_workflow.md b/python/functions/ml/comfyui_build_txt2img_workflow.md index 7c2eb281..44cb0cc3 100644 --- a/python/functions/ml/comfyui_build_txt2img_workflow.md +++ b/python/functions/ml/comfyui_build_txt2img_workflow.md @@ -39,7 +39,7 @@ params: desc: "Prefijo del PNG que SaveImage escribe en output/. keyword-only." output: "dict en API format con node_ids '3'..'9' como claves; cada valor tiene class_type + inputs. Listo para comfyui_submit_workflow." tested: true -tests: ["class_types esperados (6 nodos)", "params seed/steps/cfg/width/height reflejados", "filename_prefix en SaveImage"] +tests: ["class_types esperados (6 nodos)", "params seed/steps/cfg/width/height reflejados", "filename_prefix en SaveImage", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_txt2img_workflow.py" file_path: "python/functions/ml/comfyui_build_txt2img_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_upscale_workflow.md b/python/functions/ml/comfyui_build_upscale_workflow.md index d9acad07..b77a1f96 100644 --- a/python/functions/ml/comfyui_build_upscale_workflow.md +++ b/python/functions/ml/comfyui_build_upscale_workflow.md @@ -23,7 +23,7 @@ params: desc: "'model' (ESRGAN via UpscaleModelLoader + ImageUpscaleWithModel) o 'latent' (reescalado de pixel x2 con ImageScaleBy, sin modelo). keyword-only." output: "dict en API format. Con method='model': LoadImage '10' + UpscaleModelLoader '12' + ImageUpscaleWithModel '13' + SaveImage '9'. Con method='latent': LoadImage '10' + ImageScaleBy '13' + SaveImage '9'. Listo para comfyui_submit_workflow." tested: true -tests: ["method='model' usa UpscaleModelLoader+ImageUpscaleWithModel", "method='latent' usa ImageScaleBy sin modelo"] +tests: ["method='model' usa UpscaleModelLoader+ImageUpscaleWithModel", "method='latent' usa ImageScaleBy sin modelo", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_upscale_workflow.py" file_path: "python/functions/ml/comfyui_build_upscale_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_video_workflow.md b/python/functions/ml/comfyui_build_video_workflow.md index 0cd86612..37fd3089 100644 --- a/python/functions/ml/comfyui_build_video_workflow.md +++ b/python/functions/ml/comfyui_build_video_workflow.md @@ -35,7 +35,7 @@ params: desc: "Frames por segundo del video (CreateVideo). En LTX se usa tambien como frame_rate del LTXVConditioning. keyword-only." output: "dict en API format listo para comfyui_submit_workflow. node_ids string; cada valor con class_type + inputs. LTX devuelve 12 nodos; Wan 11. La cfg/sampler/scheduler se fijan internamente segun el modelo (LTX: cfg 3.0, euler; Wan: cfg 6.0, uni_pc/simple, shift 8.0)." tested: true -tests: ["LTX: nodos LTXV* presentes + t5xxl fp8 + ckpt real", "Wan: UNETLoader/VAELoader/ModelSamplingSD3 + umt5 + wan_2.1_vae", "params reflejados (width/height/num_frames/steps/seed/fps)", "model invalido lanza ValueError"] +tests: ["LTX: nodos LTXV* presentes + t5xxl fp8 + ckpt real", "Wan: UNETLoader/VAELoader/ModelSamplingSD3 + umt5 + wan_2.1_vae", "params reflejados (width/height/num_frames/steps/seed/fps)", "model invalido lanza ValueError", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_video_workflow.py" file_path: "python/functions/ml/comfyui_build_video_workflow.py" --- diff --git a/python/functions/ml/comfyui_build_view_3d_workflow.md b/python/functions/ml/comfyui_build_view_3d_workflow.md index 1e1512b9..8f7d5031 100644 --- a/python/functions/ml/comfyui_build_view_3d_workflow.md +++ b/python/functions/ml/comfyui_build_view_3d_workflow.md @@ -25,7 +25,7 @@ params: desc: "Alto del viewport del nodo en px. keyword-only." output: "dict en API format con un unico nodo '1'. Con animation=False: class_type 'Load3D', inputs {model_file, image, width, height}. Con animation=True: class_type 'Load3DAdvanced', inputs {model_file, viewport_state, width, height}. Cargable con comfyui_load_workflow_ui (inyecta en la UI del navegador) o POSTeable a /prompt." tested: true -tests: ["Load3D simple con model_file/width/height", "animation=True usa Load3DAdvanced"] +tests: ["Load3D simple con model_file/width/height", "animation=True usa Load3DAdvanced", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_build_view_3d_workflow.py" file_path: "python/functions/ml/comfyui_build_view_3d_workflow.py" --- diff --git a/python/functions/ml/comfyui_inject_lora.md b/python/functions/ml/comfyui_inject_lora.md index df98ec1c..29ae11d0 100644 --- a/python/functions/ml/comfyui_inject_lora.md +++ b/python/functions/ml/comfyui_inject_lora.md @@ -29,7 +29,7 @@ params: desc: "node_id cuya salida CLIP (slot 1) alimentara el LoRA. Si None, se detecta la fuente que hoy alimenta los CLIPTextEncode.clip. keyword-only." output: "copia del workflow con un nodo LoraLoader insertado (node_id = max id numerico + 1) y reconectado entre la fuente model/clip y sus consumidores." tested: true -tests: ["no muta el dict de entrada (pureza)", "inserta LoraLoader con strength correcto", "reconecta KSampler.model al LoRA"] +tests: ["no muta el dict de entrada (pureza)", "inserta LoraLoader con strength correcto", "reconecta KSampler.model al LoRA", "determinismo: misma entrada -> mismo dict (builder puro)"] test_file_path: "python/functions/ml/tests/test_comfyui_inject_lora.py" file_path: "python/functions/ml/comfyui_inject_lora.py" --- diff --git a/python/functions/ml/tests/test_comfyui_build_controlnet_workflow.py b/python/functions/ml/tests/test_comfyui_build_controlnet_workflow.py index e50c06cf..1df91064 100644 --- a/python/functions/ml/tests/test_comfyui_build_controlnet_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_controlnet_workflow.py @@ -28,3 +28,11 @@ def test_control_image_modelo_y_strength(): apply_in = node_by_ct(wf, "ControlNetApply")["inputs"] assert apply_in["strength"] == 0.65 assert node_by_ct(wf, "KSampler")["inputs"]["seed"] == 5 + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + args = ("ck.safetensors", "pose.png", "control_openpose.pth", "POS", "NEG") + a = comfyui_build_controlnet_workflow(*args, strength=0.65, seed=5) + b = comfyui_build_controlnet_workflow(*args, strength=0.65, seed=5) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_facedetailer_workflow.py b/python/functions/ml/tests/test_comfyui_build_facedetailer_workflow.py index 25b20fbe..430e48d0 100644 --- a/python/functions/ml/tests/test_comfyui_build_facedetailer_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_facedetailer_workflow.py @@ -82,3 +82,11 @@ def test_invalid_base_type_raises(): comfyui_build_facedetailer_workflow( 123, ckpt_name="dreamshaper_8.safetensors", positive="face", ) + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + kw = dict(ckpt_name="dreamshaper_8.safetensors", positive="detailed face", seed=42) + a = comfyui_build_facedetailer_workflow("portrait_00001_.png", **kw) + b = comfyui_build_facedetailer_workflow("portrait_00001_.png", **kw) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py b/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py index 3cb61835..e09f3752 100644 --- a/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_hires_fix_workflow.py @@ -48,3 +48,11 @@ def test_upscale_model_wired(): assert wf["11"]["class_type"] == "UpscaleModelLoader" assert wf["11"]["inputs"]["model_name"] == "4x_foolhardy_Remacri.pth" assert wf["12"]["inputs"]["upscale_model"] == ["11", 0] + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + kw = dict(ckpt_name="dreamshaper_8.safetensors", positive="a fox", seed=42) + a = comfyui_build_hires_fix_workflow(**kw) + b = comfyui_build_hires_fix_workflow(**kw) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_image_to_3d_workflow.py b/python/functions/ml/tests/test_comfyui_build_image_to_3d_workflow.py index 541074f7..d7bb89c6 100644 --- a/python/functions/ml/tests/test_comfyui_build_image_to_3d_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_image_to_3d_workflow.py @@ -56,3 +56,10 @@ def test_watertight_usa_voxeltomesh_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] + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + a = comfyui_build_image_to_3d_workflow("obj.png", seed=42) + b = comfyui_build_image_to_3d_workflow("obj.png", seed=42) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_img2img_workflow.py b/python/functions/ml/tests/test_comfyui_build_img2img_workflow.py index cff8f47e..63d3b733 100644 --- a/python/functions/ml/tests/test_comfyui_build_img2img_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_img2img_workflow.py @@ -28,3 +28,11 @@ def test_denoise_y_init_image(): assert ks["denoise"] == 0.45 assert ks["seed"] == 7 assert node_by_ct(wf, "LoadImage")["inputs"]["image"] == "init.png" + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + args = ("ck.safetensors", "init.png", "POS", "NEG") + a = comfyui_build_img2img_workflow(*args, seed=7) + b = comfyui_build_img2img_workflow(*args, seed=7) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_inpaint_workflow.py b/python/functions/ml/tests/test_comfyui_build_inpaint_workflow.py index 562bbf99..31c66a2b 100644 --- a/python/functions/ml/tests/test_comfyui_build_inpaint_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_inpaint_workflow.py @@ -29,3 +29,11 @@ def test_base_y_mascara_se_cargan(): assert mask == "m.png" ks = node_by_ct(wf, "KSampler")["inputs"] assert ks["seed"] == 33 and ks["denoise"] == 0.9 + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + args = ("ck.safetensors", "img.png", "mask.png", "POS", "NEG") + a = comfyui_build_inpaint_workflow(*args, seed=33) + b = comfyui_build_inpaint_workflow(*args, seed=33) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_sdxl_refiner_workflow.py b/python/functions/ml/tests/test_comfyui_build_sdxl_refiner_workflow.py index 58e0fd4a..c01b126b 100644 --- a/python/functions/ml/tests/test_comfyui_build_sdxl_refiner_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_sdxl_refiner_workflow.py @@ -31,3 +31,11 @@ def test_base_emite_ruido_sobrante_y_refiner_lo_recoge(): # Comparten el corte de pasos: el base termina donde declara base_steps. assert base["end_at_step"] == 20 assert refiner["start_at_step"] == 20 + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + args = ("base.st", "ref.st", "POS", "NEG") + a = comfyui_build_sdxl_refiner_workflow(*args, seed=9) + b = comfyui_build_sdxl_refiner_workflow(*args, seed=9) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_textured_3d_multiview_workflow.py b/python/functions/ml/tests/test_comfyui_build_textured_3d_multiview_workflow.py index 26086f74..d9c9f387 100644 --- a/python/functions/ml/tests/test_comfyui_build_textured_3d_multiview_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_textured_3d_multiview_workflow.py @@ -78,3 +78,10 @@ def test_sin_upscale_omite_nodos_remacri(): def test_views_invalido_lanza_valueerror(): with pytest.raises(ValueError): comfyui_build_textured_3d_multiview_workflow("ref.png", views=3) + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red ni estado). + a = comfyui_build_textured_3d_multiview_workflow("ref.png", views=6) + b = comfyui_build_textured_3d_multiview_workflow("ref.png", views=6) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_txt2img_workflow.py b/python/functions/ml/tests/test_comfyui_build_txt2img_workflow.py index 6c4657d3..c3ad3bfe 100644 --- a/python/functions/ml/tests/test_comfyui_build_txt2img_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_txt2img_workflow.py @@ -41,3 +41,11 @@ def test_params_se_reflejan_en_los_nodos(): def test_filename_prefix_en_saveimage(): wf = comfyui_build_txt2img_workflow("ck.safetensors", "POS", filename_prefix="demo_run") assert node_by_ct(wf, "SaveImage")["inputs"]["filename_prefix"] == "demo_run" + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + args = ("ck.safetensors", "POS", "NEG") + a = comfyui_build_txt2img_workflow(*args, seed=123) + b = comfyui_build_txt2img_workflow(*args, seed=123) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_upscale_workflow.py b/python/functions/ml/tests/test_comfyui_build_upscale_workflow.py index 22c59ca1..040d471b 100644 --- a/python/functions/ml/tests/test_comfyui_build_upscale_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_upscale_workflow.py @@ -26,3 +26,10 @@ def test_method_latent_no_usa_modelo(): assert "ImageScaleBy" in cts assert "UpscaleModelLoader" not in cts assert node_by_ct(wf, "LoadImage")["inputs"]["image"] == "img.png" + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red ni estado). + a = comfyui_build_upscale_workflow("img.png", model_name="4x-UltraSharp.pth", method="model") + b = comfyui_build_upscale_workflow("img.png", model_name="4x-UltraSharp.pth", method="model") + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_video_workflow.py b/python/functions/ml/tests/test_comfyui_build_video_workflow.py index ce47abb8..22a2b081 100644 --- a/python/functions/ml/tests/test_comfyui_build_video_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_video_workflow.py @@ -89,3 +89,10 @@ def test_params_se_reflejan_wan(): def test_model_invalido_lanza_valueerror(): with pytest.raises(ValueError): comfyui_build_video_workflow("x", model="sora") + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado). + a = comfyui_build_video_workflow("a fox running", model="ltx", seed=7) + b = comfyui_build_video_workflow("a fox running", model="ltx", seed=7) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_build_view_3d_workflow.py b/python/functions/ml/tests/test_comfyui_build_view_3d_workflow.py index 860cba20..f814310e 100644 --- a/python/functions/ml/tests/test_comfyui_build_view_3d_workflow.py +++ b/python/functions/ml/tests/test_comfyui_build_view_3d_workflow.py @@ -24,3 +24,10 @@ def test_animation_usa_load3d_advanced(): wf = comfyui_build_view_3d_workflow("mesh.glb", animation=True) assert class_types(wf) == {"Load3DAdvanced"} assert node_by_ct(wf, "Load3DAdvanced")["inputs"]["model_file"] == "mesh.glb" + + +def test_determinista(): + # Builder puro: misma entrada -> mismo dict (sin red ni estado). + a = comfyui_build_view_3d_workflow("mesh.glb", width=800, height=600) + b = comfyui_build_view_3d_workflow("mesh.glb", width=800, height=600) + assert a == b diff --git a/python/functions/ml/tests/test_comfyui_inject_lora.py b/python/functions/ml/tests/test_comfyui_inject_lora.py index 497a63bf..ca4b015b 100644 --- a/python/functions/ml/tests/test_comfyui_inject_lora.py +++ b/python/functions/ml/tests/test_comfyui_inject_lora.py @@ -43,3 +43,11 @@ def test_reconecta_el_ksampler_al_lora(): ks = next(n for n in inj.values() if n["class_type"] == "KSampler") # El KSampler debe tomar el modelo del LoraLoader, no ya del checkpoint. assert ks["inputs"]["model"][0] == lid + + +def test_determinista(): + # Builder puro: misma base + mismos args -> mismo dict (deepcopy, sin estado). + base = comfyui_build_txt2img_workflow("ck.safetensors", "POS", "NEG") + a = comfyui_inject_lora(base, "style.safetensors") + b = comfyui_inject_lora(base, "style.safetensors") + assert a == b