From 8eedb6b45a9ffc6e9c6441725e6512d028b567b3 Mon Sep 17 00:00:00 2001 From: Nick Date: Sat, 27 Dec 2025 10:03:06 +1300 Subject: [PATCH] Add widget mappings for all WanVideo workflow nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The convert_frontend_to_api() function was missing mappings for most node types, causing "Required input is missing" errors when the API received workflows in frontend format. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- handler.py | 79 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/handler.py b/handler.py index 90d24e4..ceaf765 100644 --- a/handler.py +++ b/handler.py @@ -122,46 +122,63 @@ def convert_frontend_to_api(frontend_workflow: dict) -> dict: link_id, src_node, src_slot, dst_node, dst_slot, link_type = link[:6] link_map[link_id] = (str(src_node), src_slot) + # Widget mappings for each node type: list of input names in order + WIDGET_MAPPINGS = { + "LoadImage": ["image", "upload"], + "CLIPTextEncode": ["text"], + "easy int": ["value"], + "INTConstant": ["value"], + "SaveVideo": ["filename_prefix", "format", "codec"], + "CreateVideo": ["fps"], + "RIFE VFI": ["ckpt_name", "clear_cache_after_n_frames", "multiplier", "fast_mode", "ensemble", "scale_factor"], + "CLIPLoader": ["clip_name", "type", "device"], + "GetImageSize": [], + "WanVideoTorchCompileSettings": [ + "backend", "fullgraph", "mode", "dynamic", "dynamo_cache_size_limit", + "compile_transformer_blocks_only", "compile_cache_max_entries", + "compile_single_blocks", "compile_double_blocks" + ], + "WanVideoBlockSwap": [ + "blocks_to_swap", "offload_txt_emb", "offload_img_emb", "offload_txt_clip_emb", + "offload_modulation", "cpu_offload_streams", "use_async_transfer" + ], + "WanVideoModelLoader": [ + "model", "base_precision", "quantization", "load_device", "attention_mode", "lora_scale_mode" + ], + "WanVideoLoraSelect": ["lora", "strength", "use_lora_sparse", "sparse_lora_blocks"], + "WanVideoVAELoader": ["model_name", "precision"], + "WanVideoTextEmbedBridge": [], + "WanVideoImageToVideoEncode": [ + "width", "height", "num_frames", "noise_aug_strength", + "start_latent_strength", "end_latent_strength", "image_noise_aug", + "mask_noise_aug", "force_offload" + ], + "WanVideoSampler": [ + "shift", "cfg", "steps", "seed", "seed_mode", "force_offload", "scheduler", + "riflex_freq_index", "riflex_freq_dim", "riflex_freq_scale", + "use_comfy_pbar", "start_step", "end_step", "denoise" + ], + "WanVideoDecode": [ + "enable_tiling", "tile_x", "tile_y", "tile_stride_x", "tile_stride_y", "tiling_decoder" + ], + "MathExpression|pysssss": ["expression"], + } + for node in nodes: node_id = str(node["id"]) class_type = node.get("type", "") inputs = {} - # Process widget values + # Process widget values using mappings widgets_values = node.get("widgets_values", []) + widget_names = WIDGET_MAPPINGS.get(class_type, []) - # Map widget values based on class type - # This is a simplified mapping - specific nodes may need custom handling - if class_type == "LoadImage" and len(widgets_values) >= 1: - inputs["image"] = widgets_values[0] - if len(widgets_values) >= 2: - inputs["upload"] = widgets_values[1] + for i, value in enumerate(widgets_values): + if i < len(widget_names) and widget_names[i]: + inputs[widget_names[i]] = value - elif class_type == "CLIPTextEncode" and len(widgets_values) >= 1: - inputs["text"] = widgets_values[0] - - elif class_type in ["easy int", "INTConstant"] and len(widgets_values) >= 1: - inputs["value"] = widgets_values[0] - - elif class_type == "SaveVideo" and len(widgets_values) >= 1: - inputs["filename_prefix"] = widgets_values[0] - if len(widgets_values) >= 2: - inputs["format"] = widgets_values[1] - if len(widgets_values) >= 3: - inputs["codec"] = widgets_values[2] - - elif class_type == "CreateVideo" and len(widgets_values) >= 1: - inputs["frame_rate"] = widgets_values[0] - - elif class_type == "RIFE VFI" and len(widgets_values) >= 1: - inputs["ckpt_name"] = widgets_values[0] - if len(widgets_values) >= 2: - inputs["clear_cache_after_n_frames"] = widgets_values[1] - if len(widgets_values) >= 3: - inputs["multiplier"] = widgets_values[2] - - # Process node inputs (connections) + # Process node inputs (connections) - these override widget values for inp in node.get("inputs", []): inp_name = inp["name"] link_id = inp.get("link")