diff --git a/nodes/wan22/latent_io.py b/nodes/wan22/latent_io.py index 1fdb54e..880d265 100644 --- a/nodes/wan22/latent_io.py +++ b/nodes/wan22/latent_io.py @@ -8,6 +8,10 @@ Registered nodes: LoadLatents_FromFolder_I2V_Pipe_MXD Load Latent Batch Pipe MXD LatentPipeUnpack_MXD Unpack Latent Pipe MXD +Plus three DEPRECATED legacy-key aliases (LoadLatent_WithParams, +LoadLatents_FromFolder_WithParams, SaveLatentMXD) so workflows saved against +the previously published keys still load. See the note above the mappings. + Route: GET /mxd/latents/files (fresh re-scan for the run_folder queuing loop). Latents are stored under /latents. Each .latent embeds the source @@ -1311,6 +1315,33 @@ class LatentPipeUnpack_MXD: ) +######################################################################################################################## +# Legacy key aliases +# +# These three nodes were published under different mapping keys before the +# VACE/I2V latent nodes were consolidated. ComfyUI matches saved workflows by +# MAPPING KEY, not display name, so without these a workflow built against the +# released version shows a red missing-node box even though a node with the +# identical name ships right here. +# +# Thin subclasses rather than extra entries pointing at the same class, so +# DEPRECATED lands only on the alias: the frontend keeps deprecated nodes out +# of the search menu (there is a setting to show them), which means old +# workflows load silently without cluttering search with duplicates. +# +# Do not "clean these up" — deleting one re-breaks every workflow using it. +class LoadLatent_WithParams(LoadLatent_I2V_MXD): + DEPRECATED = True + + +class LoadLatents_FromFolder_WithParams(LoadLatents_FromFolder_I2V_MXD): + DEPRECATED = True + + +class SaveLatentMXD(SaveLatent_I2V_MXD): + DEPRECATED = True + + NODE_CLASS_MAPPINGS = { "SaveLatent_I2V_MXD": SaveLatent_I2V_MXD, "LoadLatent_I2V_MXD": LoadLatent_I2V_MXD, @@ -1318,8 +1349,14 @@ NODE_CLASS_MAPPINGS = { "LoadLatent_I2V_Pipe_MXD": LoadLatent_I2V_Pipe_MXD, "LoadLatents_FromFolder_I2V_Pipe_MXD": LoadLatents_FromFolder_I2V_Pipe_MXD, "LatentPipeUnpack_MXD": LatentPipeUnpack_MXD, + # Legacy keys — see the note above. + "LoadLatent_WithParams": LoadLatent_WithParams, + "LoadLatents_FromFolder_WithParams": LoadLatents_FromFolder_WithParams, + "SaveLatentMXD": SaveLatentMXD, } +# The legacy aliases deliberately get NO display name — an unnamed, DEPRECATED +# node stays out of the search menu entirely. NODE_DISPLAY_NAME_MAPPINGS = { "SaveLatent_I2V_MXD": "Save Latent MXD", "LoadLatent_I2V_MXD": "Load Latent MXD", diff --git a/scripts/node_schema_baseline.json b/scripts/node_schema_baseline.json index df69546..6d73ca3 100644 --- a/scripts/node_schema_baseline.json +++ b/scripts/node_schema_baseline.json @@ -1,5 +1,5 @@ { - "node_count": 62, + "node_count": 65, "nodes": { "BboxDetectorCombinedBatchMXD": { "category": "MXD/Detector", @@ -1327,6 +1327,65 @@ "MXD_LATENT_PIPE" ] }, + "LoadLatent_WithParams": { + "category": "MXD/Latents", + "class": "LoadLatent_WithParams", + "display_name": null, + "function": "load", + "input_types": { + "required": { + "latent": { + "type": { + "combo": "empty", + "dynamic": true + } + }, + "refresh_before_run": { + "config": { + "default": false, + "tooltip": "When run_folder is on, re-scan the latents folder for new files right before the queuing loop starts, instead of using the dropdown list as of whenever it was last populated. Use this when another workflow is still writing latents into this folder as you queue this one." + }, + "type": "BOOLEAN" + }, + "run_folder": { + "config": { + "default": false, + "tooltip": "When enabled, hitting Queue Prompt auto-queues every latent in this file's folder, one after another, instead of just the selected file." + }, + "type": "BOOLEAN" + } + } + }, + "output_node": false, + "return_names": [ + "shift", + "positive", + "negative", + "samples", + "steps", + "cfg", + "sampler_name", + "scheduler", + "end_at_step", + "filename_prefix", + "trim_latent", + "high_workflow" + ], + "return_types": [ + "FLOAT", + "CONDITIONING", + "CONDITIONING", + "LATENT", + "INT", + "FLOAT", + "['euler', 'euler_cfg_pp', 'euler_ancestral', 'euler_ancestral_cfg_pp', 'heun', 'heunpp2', 'exp_heun_2_x0', 'exp_heun_2_x0_sde', 'dpm_2', 'dpm_2_ancestral', 'lms', 'dpm_fast', 'dpm_adaptive', 'dpmpp_2s_ancestral', 'dpmpp_2s_ancestral_cfg_pp', 'dpmpp_sde', 'dpmpp_sde_gpu', 'dpmpp_2m', 'dpmpp_2m_cfg_pp', 'dpmpp_2m_sde', 'dpmpp_2m_sde_gpu', 'dpmpp_2m_sde_heun', 'dpmpp_2m_sde_heun_gpu', 'dpmpp_3m_sde', 'dpmpp_3m_sde_gpu', 'ddpm', 'lcm', 'ipndm', 'ipndm_v', 'deis', 'res_multistep', 'res_multistep_cfg_pp', 'res_multistep_ancestral', 'res_multistep_ancestral_cfg_pp', 'gradient_estimation', 'gradient_estimation_cfg_pp', 'er_sde', 'seeds_2', 'seeds_3', 'sa_solver', 'sa_solver_pece', 'ddim', 'uni_pc', 'uni_pc_bh2']", + "['simple', 'sgm_uniform', 'karras', 'exponential', 'ddim_uniform', 'beta', 'normal', 'linear_quadratic', 'kl_optimal']", + "INT", + "STRING", + "INT", + "STRING" + ] + }, "LoadLatents_FromFolder_I2V_MXD": { "category": "MXD/Latents", "class": "LoadLatents_FromFolder_I2V_MXD", @@ -1393,6 +1452,49 @@ "MXD_LATENT_PIPE" ] }, + "LoadLatents_FromFolder_WithParams": { + "category": "MXD/Latents", + "class": "LoadLatents_FromFolder_WithParams", + "display_name": null, + "function": "load_batch_i2v", + "input_types": { + "required": { + "subfolder": { + "type": { + "combo": "nonempty", + "dynamic": true + } + } + } + }, + "output_node": false, + "return_names": [ + "shift", + "positive", + "negative", + "samples", + "steps", + "cfg", + "sampler_name", + "scheduler", + "end_at_step", + "filename_prefix", + "trim_latent" + ], + "return_types": [ + "FLOAT", + "CONDITIONING", + "CONDITIONING", + "LATENT", + "INT", + "FLOAT", + "['euler', 'euler_cfg_pp', 'euler_ancestral', 'euler_ancestral_cfg_pp', 'heun', 'heunpp2', 'exp_heun_2_x0', 'exp_heun_2_x0_sde', 'dpm_2', 'dpm_2_ancestral', 'lms', 'dpm_fast', 'dpm_adaptive', 'dpmpp_2s_ancestral', 'dpmpp_2s_ancestral_cfg_pp', 'dpmpp_sde', 'dpmpp_sde_gpu', 'dpmpp_2m', 'dpmpp_2m_cfg_pp', 'dpmpp_2m_sde', 'dpmpp_2m_sde_gpu', 'dpmpp_2m_sde_heun', 'dpmpp_2m_sde_heun_gpu', 'dpmpp_3m_sde', 'dpmpp_3m_sde_gpu', 'ddpm', 'lcm', 'ipndm', 'ipndm_v', 'deis', 'res_multistep', 'res_multistep_cfg_pp', 'res_multistep_ancestral', 'res_multistep_ancestral_cfg_pp', 'gradient_estimation', 'gradient_estimation_cfg_pp', 'er_sde', 'seeds_2', 'seeds_3', 'sa_solver', 'sa_solver_pece', 'ddim', 'uni_pc', 'uni_pc_bh2']", + "['simple', 'sgm_uniform', 'karras', 'exponential', 'ddim_uniform', 'beta', 'normal', 'linear_quadratic', 'kl_optimal']", + "INT", + "STRING", + "INT" + ] + }, "LoadVideoFromFolderMXD": { "category": "MXD/Video", "class": "LoadVideoFromFolderMXD", @@ -2076,6 +2178,67 @@ "STRING" ] }, + "SaveLatentMXD": { + "category": "MXD/Latents", + "class": "SaveLatentMXD", + "display_name": null, + "function": "save_only", + "input_types": { + "hidden": { + "extra_pnginfo": { + "type": "EXTRA_PNGINFO" + }, + "prompt": { + "type": "PROMPT" + }, + "unique_id": { + "type": "UNIQUE_ID" + } + }, + "optional": { + "trim_latent": { + "config": { + "default": 0, + "max": 10000, + "min": 0, + "step": 1, + "tooltip": "VACE 2.2 trim_latent value to preserve with this latent. Usually 0 or 1. Ignored for t2v/i2v." + }, + "type": "INT" + } + }, + "required": { + "filename_prefix": { + "config": { + "default": "ComfyUI", + "tooltip": "Prefix for saved files" + }, + "type": "STRING" + }, + "negative": { + "config": { + "tooltip": "Negative CONDITIONING to save alongside the latent." + }, + "type": "CONDITIONING" + }, + "positive": { + "config": { + "tooltip": "Positive CONDITIONING to save alongside the latent." + }, + "type": "CONDITIONING" + }, + "samples": { + "config": { + "tooltip": "Latent to save." + }, + "type": "LATENT" + } + } + }, + "output_node": true, + "return_names": null, + "return_types": [] + }, "SaveLatent_I2V_MXD": { "category": "MXD/Latents", "class": "SaveLatent_I2V_MXD",