From f74b90ea369fa43411999317a393014bdf517dbe Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Sun, 18 Oct 2026 10:09:19 +0200 Subject: [PATCH 1/2] feat(controlnet): add Qwen Image Fun-ControlNet-Union with canvas control layers Add alibaba-pai's VACE-style control branch for Qwen-Image: identification, loader, the qwen_image_control node and control/inpaint conditioning in the denoise, injected through forward hooks on the diffusers transformer. The canvas gets a Qwen Image ControlNet layer kind with inpaint/outpaint feeding and a grayscale filter; the denoise now reserves working memory for its activations. --- .../03.Models/03.model-format-support.mdx | 4 +- .../03.Models/Local Models/qwen-image.mdx | 36 +- .../Users Guide/07.Canvas/02.canvas-guide.mdx | 4 +- .../Optimization/low-vram-mode.mdx | 4 +- .../qwen_image/qwen_image_control.py | 118 ++ .../qwen_image/qwen_image_denoise.py | 213 ++- .../backend/architectures/defs/qwen_image.py | 1 + .../backend/architectures/facets/features.py | 6 +- invokeai/backend/fun_controlnet/__init__.py | 8 + invokeai/backend/fun_controlnet/branch.py | 84 ++ .../backend/fun_controlnet/conditioning.py | 61 + invokeai/backend/fun_controlnet/hooks.py | 110 ++ invokeai/backend/fun_controlnet/qwen_image.py | 157 +++ .../model_manager/configs/controlnet.py | 48 + .../backend/model_manager/configs/factory.py | 2 + .../load/model_loaders/fun_controlnet.py | 44 + .../model_manager/starter_models/__init__.py | 3 + .../starter_models/qwen_image.py | 10 + invokeai/frontend/api/openapi.json | 534 +++++++- invokeai/frontend/api/schema.ts | 293 ++++- .../frontend/webv2/public/locales/en.json | 4 + .../architectureCapabilities.json | 4 +- .../__snapshots__/generateGraphNodeTypes.json | 3 +- .../qwenImageControlCanvasGraphs.json | 1160 +++++++++++++++++ .../core/architectureCapabilities.test.ts | 1 + .../core/canvas/addControlLayers.test.ts | 128 ++ .../core/canvas/addControlLayers.ts | 60 +- .../core/canvas/compileCanvasGraph.test.ts | 151 +++ .../core/canvas/compileCanvasGraph.ts | 47 +- .../core/canvas/controlValidation.test.ts | 45 + .../core/canvas/controlValidation.ts | 35 +- .../features/generation/core/graph.test.ts | 7 + .../src/features/generation/core/graph.ts | 2 + .../webv2/src/features/generation/graph.ts | 1 + .../src/workbench/canvas-engine/contracts.ts | 2 +- .../canvas-operations/filterGraphs.test.ts | 55 +- .../canvas-operations/filterGraphs.ts | 27 +- .../src/workbench/canvasMigration.test.ts | 24 + .../webv2/src/workbench/canvasMigration.ts | 12 +- .../src/workbench/controlAdapters.test.ts | 35 + .../webv2/src/workbench/controlAdapters.ts | 17 +- .../src/workbench/controlLayerChecks.test.ts | 33 +- .../webv2/src/workbench/controlLayerChecks.ts | 6 +- .../invoke/prepareCanvasInvocation.test.ts | 97 ++ .../ControlLayerSettings.browser.test.tsx | 77 +- .../widgets/layers/ControlLayerSettings.tsx | 3 +- .../layers/ControlLayerWarningIcon.tsx | 2 +- .../layers/controlModelOptions.test.ts | 27 + .../workbench/widgets/layers/layerOps.test.ts | 7 + ...test_frontend_qwen_image_control_graphs.py | 210 +++ .../invocations/test_qwen_image_control.py | 504 +++++++ .../test_qwen_image_packed_models.py | 11 +- tests/backend/architectures/test_features.py | 1 + tests/backend/fun_controlnet/conftest.py | 50 + .../test_qwen_image_control_conditioning.py | 145 +++ .../test_qwen_image_fun_control.py | 276 ++++ .../test_qwen_image_fun_controlnet_config.py | 172 +++ .../qwen_image_fun_controlnet_keys.py | 193 +++ .../qwen_image_instantx_controlnet_keys.py | 63 + .../model_manager/load/test_fp8_capability.py | 1 + .../load/test_fun_controlnet_loader.py | 98 ++ ...2512-Fun-Controlnet-Union-2602.safetensors | 3 + .../__test_metadata__.json | 3 + 63 files changed, 5424 insertions(+), 118 deletions(-) create mode 100644 invokeai/app/invocations/qwen_image/qwen_image_control.py create mode 100644 invokeai/backend/fun_controlnet/__init__.py create mode 100644 invokeai/backend/fun_controlnet/branch.py create mode 100644 invokeai/backend/fun_controlnet/conditioning.py create mode 100644 invokeai/backend/fun_controlnet/hooks.py create mode 100644 invokeai/backend/fun_controlnet/qwen_image.py create mode 100644 invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py create mode 100644 invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json create mode 100644 tests/app/invocations/test_frontend_qwen_image_control_graphs.py create mode 100644 tests/app/invocations/test_qwen_image_control.py create mode 100644 tests/backend/fun_controlnet/conftest.py create mode 100644 tests/backend/fun_controlnet/test_qwen_image_control_conditioning.py create mode 100644 tests/backend/fun_controlnet/test_qwen_image_fun_control.py create mode 100644 tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py create mode 100644 tests/backend/model_manager/load/state_dicts/qwen_image_fun_controlnet_keys.py create mode 100644 tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py create mode 100644 tests/backend/model_manager/load/test_fun_controlnet_loader.py create mode 100644 tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors create mode 100644 tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/__test_metadata__.json diff --git a/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx b/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx index 7279c395b1a..a878bc8e832 100644 --- a/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx +++ b/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx @@ -1,7 +1,7 @@ --- title: Model Format Support description: Which file formats and quantizations InvokeAI loads for every model family, text encoder, VAE and adapter. -lastUpdated: 2026-10-16 +lastUpdated: 2026-10-18 sidebar: order: 3 --- @@ -102,7 +102,7 @@ not check, so a quantized file there fails with an unclear error or decodes inco | SDXL | ✓ (LyCORIS, Diffusers, OMI) | ✓ | IP-Adapter, T2I-Adapter, textual inversion | | FLUX.1 | ✓ (LyCORIS, Diffusers, OMI) | ✓ | Control LoRA, IP-Adapter, Redux | | FLUX.2, Z-Image | ✓ (LyCORIS, Diffusers) | Z-Image only | | -| Qwen-Image, Krea-2, Wan 2.2, Anima | ✓ (LyCORIS/kohya, including LoKR where noted on the family page) | Anima (ControlNet-LLLite) | | +| Qwen-Image, Krea-2, Wan 2.2, Anima | ✓ (LyCORIS/kohya, including LoKR where noted on the family page) | Qwen-Image (single-file checkpoint), Anima (ControlNet-LLLite) | | | LTX-2, MiniMax H3 | ✓ (plain low-rank; LoKR, LoHA and DoRA are refused) | ✗ | | | SD 3, CogView4, Ideogram 4, ERNIE-Image, Qwen-Image-2.1 | ✗ | ✗ | | diff --git a/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx b/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx index a682e1011b5..a67f0d8f342 100644 --- a/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx +++ b/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx @@ -1,7 +1,7 @@ --- title: Qwen Image -description: Generate and edit images with the Qwen Image 2512 text-to-image model and the Qwen Image Edit 2511 reference-image editing model, including GGUF installs and the Lightning LoRAs. -lastUpdated: 2026-09-30 +description: Generate and edit images with the Qwen Image 2512 text-to-image model and the Qwen Image Edit 2511 reference-image editing model, including GGUF installs, the Lightning LoRAs and the Fun-ControlNet-Union. +lastUpdated: 2026-10-18 sidebar: order: 8 --- @@ -17,11 +17,13 @@ variants: person in image 2"). The variant is detected automatically on install. Both variants can also run text-to-image, -image-to-image, inpainting and outpainting on the Canvas; only the Edit variant accepts reference images. +image-to-image, inpainting and outpainting on the Canvas; only the Edit variant accepts reference images, +and only the text-to-image variant takes a [ControlNet](#controlnet). ## License -Qwen Image 2512, Qwen Image Edit 2511, the Lightning LoRAs and the Qwen2.5-VL text encoder are released under **Apache 2.0**, which allows commercial use. None of the downloads is gated. +Qwen Image 2512, Qwen Image Edit 2511, the Lightning LoRAs, the Qwen2.5-VL text encoder and the Qwen Image +ControlNet Union are released under **Apache 2.0**, which allows commercial use. None of the downloads is gated. This is a summary, not legal advice. Read the full license on the model's HuggingFace page before using a model commercially. @@ -125,6 +127,29 @@ Image**; connect an **Image to Latents - Qwen Image** node to the **Reference La Qwen Image LoRAs (diffusers PEFT, Kohya and LoKR formats) are supported and apply to the transformer. In the workflow editor use **Apply LoRA - Qwen Image** or **Apply LoRA Collection - Qwen Image**. +## ControlNet + +The **Qwen Image ControlNet Union** starter model is alibaba-pai's *Fun-ControlNet-Union* for Qwen Image 2512 +(~3.5 GB, Apache 2.0). One model handles every condition: **Canny**, **HED**, **Depth**, **Pose**, **MLSD**, +**Scribble** and **Gray** control images, plus **inpainting**. It is trained for the text-to-image transformer: +with a Qwen Image Edit model selected, a control layer's settings and the **Invoke** button say that the +ControlNet is not compatible, and nothing is generated until the layer is disabled or the model changed. + +On the Canvas, add a **Control Layer** while a Qwen Image model is selected. Its adapter type is **Qwen Image +ControlNet** and its pixels are the control image; the layer's **Filter** turns a raster into one of the +conditions (Canny, HED, Depth Anything, DW Openpose, MLSD, Scribble or Grayscale). The layer's **Weight** is +the model's control scale: it ranges from `0` to `2`, starts at `0.85`, and `0.70` to `0.95` is the +recommended range. **Only one** Qwen Image control layer can be used per generation. + +When the Canvas inpaints or outpaints with a control layer present, the ControlNet also receives the image being +regenerated and the mask of the region as its inpainting condition. Without a control layer, inpainting and +outpainting work as before. + +In the workflow editor, the same thing is the **Qwen Image ControlNet** node feeding the **Control** input of +**Denoise - Qwen Image**. Give it a control **Image**, an **Inpaint Image** together with its **Inpaint Mask** +(white is regenerated), or both. **Denoise - Qwen Image** then also needs its **VAE** input connected, which it +uses to encode these images. + ## PiD super-resolution decode Qwen Image works with [PiD Decode](/users-guide/image-generation/advanced-topics/pid-decode/), which replaces the VAE @@ -137,7 +162,8 @@ Decoder Qwen-Image (2K to 4K)* decoders (including an int8 build of the latter) | ------------------------------------------- | ------------------------------------------------------------------- | | **Main Model - Qwen Image** | Loads the transformer, VAE and Qwen VL encoder (or a component source) | | **Prompt - Qwen Image** | Encodes the prompt and any reference images | -| **Denoise - Qwen Image** | Runs sampling; accepts reference latents, img2img latents and masks | +| **Denoise - Qwen Image** | Runs sampling; accepts reference latents, img2img latents, masks and a ControlNet | +| **Qwen Image ControlNet** | Configures the ControlNet Union: control image and/or inpaint image with mask, scale, step range | | **Image to Latents - Qwen Image** | VAE encode | | **Latents to Image - Qwen Image** | VAE decode | | **Latents to Image - Qwen-Image + PiD (4x SR)** | PiD super-resolution decode | diff --git a/docs/src/content/docs/Users Guide/07.Canvas/02.canvas-guide.mdx b/docs/src/content/docs/Users Guide/07.Canvas/02.canvas-guide.mdx index 01246c552ef..34b59a91a07 100644 --- a/docs/src/content/docs/Users Guide/07.Canvas/02.canvas-guide.mdx +++ b/docs/src/content/docs/Users Guide/07.Canvas/02.canvas-guide.mdx @@ -1,7 +1,7 @@ --- title: Canvas guide description: A detailed guide to the Canvas — its tools and their options, navigation, the header buttons, the generation frame, selections, transform, filters, the staging area, menus, settings and keyboard shortcuts. -lastUpdated: 2026-10-05 +lastUpdated: 2026-10-18 --- import { Image } from 'astro:assets'; @@ -117,7 +117,7 @@ To crop a layer to the generation frame, choose **Crop layer to bbox** from its * **Edge detection** — Canny, HED, Lineart, Lineart Anime, MLSD, PiDiNet and Scribble. * **Depth & normal** — Depth Anything and Normal map. * **Pose & face** — DW Openpose and Mediapipe Face. -* **Color & tone** — Color map and Adjust image. +* **Color & tone** — Color map, Adjust image and Grayscale. * **Blur & noise** — Content shuffle, Blur and Noise. * **Upscale** — an upscaling model. diff --git a/docs/src/content/docs/configuration/Optimization/low-vram-mode.mdx b/docs/src/content/docs/configuration/Optimization/low-vram-mode.mdx index 408b8ce1b1e..c7127113da8 100644 --- a/docs/src/content/docs/configuration/Optimization/low-vram-mode.mdx +++ b/docs/src/content/docs/configuration/Optimization/low-vram-mode.mdx @@ -210,8 +210,8 @@ To always decode untiled unless you ask for tiling, turn this off. A decode too auto_tiled_decode: false ``` -- **Always tile:** set `force_tiled_decode: true` in `invokeai.yaml`. It covers the VAE decode and encode for SD1.5/SDXL, FLUX.1, FLUX.2, Z-Image, Qwen-Image and Qwen-Image-2.1, the Anima encode, the control image of a Z-Image ControlNet, and the Krea-2 style reference. Other model families (for example SD3, Wan and LTX-2) ignore it. -- **Per node:** the SD, FLUX.1, FLUX.2, Z-Image, Qwen-Image and Qwen-Image-2.1 **Latents to Image** and **Image to Latents** nodes, and **Image to Latents - Anima**, have **Tiled** and **Tile Size** fields for workflows. So does the **Z-Image ControlNet** node, for the control image the denoise encodes. The [Upscale panel](/users-guide/image-generation/upscale/) turns tiling on by itself. +- **Always tile:** set `force_tiled_decode: true` in `invokeai.yaml`. It covers the VAE decode and encode for SD1.5/SDXL, FLUX.1, FLUX.2, Z-Image, Qwen-Image and Qwen-Image-2.1, the Anima encode, the control image of a Z-Image ControlNet, the control and inpaint images of a Qwen Image ControlNet, and the Krea-2 style reference. Other model families (for example SD3, Wan and LTX-2) ignore it. +- **Per node:** the SD, FLUX.1, FLUX.2, Z-Image, Qwen-Image and Qwen-Image-2.1 **Latents to Image** and **Image to Latents** nodes, and **Image to Latents - Anima**, have **Tiled** and **Tile Size** fields for workflows. So do the **Z-Image ControlNet** and **Qwen Image ControlNet** nodes, for the images the denoise encodes. The [Upscale panel](/users-guide/image-generation/upscale/) turns tiling on by itself. - **Automatic retry:** if a FLUX.1, FLUX.2, Z-Image or Anima decode, or a FLUX.1 or FLUX.2 encode, runs out of memory, InvokeAI retries it once with tiling and logs that it did. A tiled decode is not pixel-identical to a single-pass one. The VAE looks at the whole image at once, so the difference is spread over the image rather than limited to the tile seams; it is small (for a 1024x1024 FLUX.2 Klein image, 5.6 of 255 per pixel value on average, with no visible seams), but the same seed will not reproduce an untiled result exactly. diff --git a/invokeai/app/invocations/qwen_image/qwen_image_control.py b/invokeai/app/invocations/qwen_image/qwen_image_control.py new file mode 100644 index 00000000000..86404e17962 --- /dev/null +++ b/invokeai/app/invocations/qwen_image/qwen_image_control.py @@ -0,0 +1,118 @@ +"""Qwen Image ControlNet: the alibaba-pai Fun-ControlNet-Union for spatial control and inpainting.""" + +from typing import Optional + +from pydantic import BaseModel, Field, model_validator + +from invokeai.app.invocations.baseinvocation import ( + BaseInvocation, + BaseInvocationOutput, + Classification, + invocation, + invocation_output, +) +from invokeai.app.invocations.fields import FieldDescriptions, ImageField, InputField, OutputField +from invokeai.app.invocations.model import ModelIdentifierField +from invokeai.app.invocations.util import validate_begin_end_step +from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType +from invokeai.backend.util.qwen_image_vae import QWEN_IMAGE_VAE_MIN_TILE_SIZE + +_CONTROL_SCALE_DESCRIPTION = "Strength of the control signal. Recommended range: 0.70-0.95." +_BEGIN_DESCRIPTION = "When the control is first applied (% of total steps)" +_END_DESCRIPTION = "When the control is last applied (% of total steps)" +_TILE_SIZE_DESCRIPTION = ( + f"{FieldDescriptions.vae_tile_size} Values between 1 and {QWEN_IMAGE_VAE_MIN_TILE_SIZE} are raised to " + f"{QWEN_IMAGE_VAE_MIN_TILE_SIZE}." +) + + +class QwenImageControlField(BaseModel): + """Qwen Image Fun-ControlNet conditioning: a control image, an inpaint image with its mask, or both.""" + + image_name: str | None = Field(default=None, description="The preprocessed control image (Canny, depth, pose, ...)") + inpaint_image_name: str | None = Field(default=None, description="The image to inpaint") + inpaint_mask_name: str | None = Field(default=None, description="The inpaint mask; white is regenerated") + control_model: ModelIdentifierField = Field(description="The Qwen Image ControlNet model") + control_context_scale: float = Field(default=0.85, ge=0.0, le=2.0, description=_CONTROL_SCALE_DESCRIPTION) + begin_step_percent: float = Field(default=0.0, ge=0.0, le=1.0, description=_BEGIN_DESCRIPTION) + end_step_percent: float = Field(default=1.0, ge=0.0, le=1.0, description=_END_DESCRIPTION) + tiled: bool = Field( + default=False, + description="Encode the control images in tiles. The denoise encodes them at generation size, which for an " + "upscale is the enlarged frame -- too large for an untiled encode on consumer hardware.", + ) + tile_size: int = Field(default=0, ge=0, multiple_of=8, description=_TILE_SIZE_DESCRIPTION) + + +@invocation_output("qwen_image_control_output") +class QwenImageControlOutput(BaseInvocationOutput): + """Qwen Image Control output containing control configuration.""" + + control: QwenImageControlField = OutputField(description="Qwen Image control conditioning") + + +@invocation( + "qwen_image_control", + title="Qwen Image ControlNet", + tags=["image", "qwen_image", "control", "controlnet", "inpaint"], + category="conditioning", + version="1.0.0", + classification=Classification.Prototype, +) +class QwenImageControlInvocation(BaseInvocation): + """Configure the Qwen Image Fun-ControlNet-Union for spatial control, inpainting, or both. + + Takes a preprocessed control image (Canny, HED, depth, pose, MLSD, ...) and/or an image to inpaint with its mask + (white is regenerated), plus the Qwen Image ControlNet model. Recommended control scale: 0.70-0.95. + """ + + image: Optional[ImageField] = InputField( + default=None, description="The preprocessed control image (Canny, HED, depth, pose, MLSD, ...)" + ) + inpaint_image: Optional[ImageField] = InputField( + default=None, description="The image to inpaint. Goes together with the inpaint mask." + ) + inpaint_mask: Optional[ImageField] = InputField( + default=None, + description="The inpaint mask: white is regenerated, black is kept. Goes together with the inpaint image.", + ) + control_model: ModelIdentifierField = InputField( + description=FieldDescriptions.controlnet_model, + title="Control Model", + ui_model_base=BaseModelType.QwenImage, + ui_model_type=ModelType.ControlNet, + ) + control_context_scale: float = InputField( + default=0.85, ge=0.0, le=2.0, description=_CONTROL_SCALE_DESCRIPTION, title="Control Scale" + ) + begin_step_percent: float = InputField(default=0.0, ge=0.0, le=1.0, description=_BEGIN_DESCRIPTION) + end_step_percent: float = InputField(default=1.0, ge=0.0, le=1.0, description=_END_DESCRIPTION) + tiled: bool = InputField(default=False, description=FieldDescriptions.tiled) + # NOTE: tile_size = 0 is a special value, as on the Qwen Image VAE nodes: the workflow UI cannot set None. + tile_size: int = InputField(default=0, ge=0, multiple_of=8, description=_TILE_SIZE_DESCRIPTION) + + @model_validator(mode="after") + def validate_begin_end_step_percent(self): + validate_begin_end_step(self.begin_step_percent, self.end_step_percent) + return self + + def invoke(self, context: InvocationContext) -> QwenImageControlOutput: + # Checked here rather than by a validator: connected inputs are filled in at execution time. + if (self.inpaint_image is None) != (self.inpaint_mask is None): + raise ValueError("The inpaint image and the inpaint mask go together: connect both or neither.") + if self.image is None and self.inpaint_image is None: + raise ValueError("Connect a control image, an inpaint image with its mask, or both.") + return QwenImageControlOutput( + control=QwenImageControlField( + image_name=self.image.image_name if self.image is not None else None, + inpaint_image_name=self.inpaint_image.image_name if self.inpaint_image is not None else None, + inpaint_mask_name=self.inpaint_mask.image_name if self.inpaint_mask is not None else None, + control_model=self.control_model, + control_context_scale=self.control_context_scale, + begin_step_percent=self.begin_step_percent, + end_step_percent=self.end_step_percent, + tiled=self.tiled, + tile_size=self.tile_size, + ) + ) diff --git a/invokeai/app/invocations/qwen_image/qwen_image_denoise.py b/invokeai/app/invocations/qwen_image/qwen_image_denoise.py index 2f63e215783..046e4a7b4de 100644 --- a/invokeai/app/invocations/qwen_image/qwen_image_denoise.py +++ b/invokeai/app/invocations/qwen_image/qwen_image_denoise.py @@ -5,6 +5,7 @@ import torch import torchvision.transforms as tv_transforms from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformer2DModel +from PIL import Image from torchvision.transforms.functional import resize as tv_resize from tqdm import tqdm @@ -20,9 +21,15 @@ WithBoard, WithMetadata, ) -from invokeai.app.invocations.model import TransformerField +from invokeai.app.invocations.model import TransformerField, VAEField from invokeai.app.invocations.primitives import LatentsOutput +from invokeai.app.invocations.qwen_image.qwen_image_control import QwenImageControlField +from invokeai.app.invocations.vae.qwen_image_image_to_latents import QwenImageImageToLatentsInvocation from invokeai.app.services.shared.invocation_context import InvocationContext +from invokeai.backend.fun_controlnet.conditioning import build_qwen_image_control_context +from invokeai.backend.fun_controlnet.hooks import FunControlHooks, install_fun_control, should_apply +from invokeai.backend.fun_controlnet.qwen_image import QwenImageFunControlBranch +from invokeai.backend.model_manager.load.load_base import LoadedModel from invokeai.backend.model_manager.taxonomy import BaseModelType from invokeai.backend.patches.layer_patcher import LayerPatcher, PatchSpec from invokeai.backend.patches.lora_conversions.qwen_image_lora_constants import ( @@ -31,8 +38,12 @@ from invokeai.backend.patches.model_patch_raw import ModelPatchRaw from invokeai.backend.quantization.dequantizing_linear import peak_dequant_transient_bytes, requires_sidecar_patching from invokeai.backend.rectified_flow.rectified_flow_inpaint_extension import RectifiedFlowInpaintExtension -from invokeai.backend.stable_diffusion.diffusers_pipeline import PipelineIntermediateState +from invokeai.backend.stable_diffusion.diffusers_pipeline import ( + PipelineIntermediateState, + image_resized_to_grid_as_tensor, +) from invokeai.backend.stable_diffusion.diffusion.conditioning_data import QwenImageConditioningInfo +from invokeai.backend.util.attention import sdpa_score_matrix_bytes from invokeai.backend.util.devices import TorchDevice from invokeai.backend.util.sage_attention import sage_attention_scope @@ -42,7 +53,7 @@ title="Denoise - Qwen Image", tags=["image", "qwen_image"], category="image", - version="1.0.0", + version="1.1.0", classification=Classification.Prototype, ) class QwenImageDenoiseInvocation(BaseInvocation, WithMetadata, WithBoard): @@ -84,6 +95,16 @@ class QwenImageDenoiseInvocation(BaseInvocation, WithMetadata, WithBoard): "When set, uses a fixed shift (e.g. 3.0 for Lightning LoRAs) instead of the default dynamic shifting. " "Leave unset for the base model's default schedule.", ) + control: Optional[QwenImageControlField] = InputField( + default=None, + description="Qwen Image ControlNet conditioning: spatial control (Canny, depth, pose, ...) and/or inpainting.", + input=Input.Connection, + ) + vae: Optional[VAEField] = InputField( + default=None, + description=FieldDescriptions.vae + " Required for control conditioning.", + input=Input.Connection, + ) @torch.no_grad() def invoke(self, context: InvocationContext) -> LatentsOutput: @@ -251,6 +272,11 @@ def _run_diffusion(self, context: InvocationContext): transformer_info = context.models.load(self.transformer.transformer) assert isinstance(transformer_info.model, QwenImageTransformer2DModel) + has_zero_cond_t = bool( + getattr(transformer_info.model, "zero_cond_t", False) + or getattr(transformer_info.model.config, "zero_cond_t", False) + ) + control_branch_info = self._load_control_branch(context, has_zero_cond_t) # Load conditioning pos_prompt_embeds, pos_prompt_mask = self._load_text_conditioning( @@ -392,12 +418,8 @@ def _run_diffusion(self, context: InvocationContext): # Pack latents into 2x2 patches: (B, C, H, W) -> (B, H/2*W/2, C*4) latents = self._pack_latents(latents, 1, out_channels, latent_height, latent_width) - # Determine whether the model uses reference latent conditioning (zero_cond_t). # Edit models (zero_cond_t=True) expect [noisy_patches ; ref_patches] in the sequence. # Txt2img models (zero_cond_t=False) only take noisy patches. - has_zero_cond_t = getattr(transformer_info.model, "zero_cond_t", False) or getattr( - transformer_info.model.config, "zero_cond_t", False - ) use_ref_latents = has_zero_cond_t ref_latents_packed = None @@ -457,19 +479,71 @@ def _run_diffusion(self, context: InvocationContext): ) noisy_seq_len = latents.shape[1] + model_input_seq_len = noisy_seq_len + (ref_latents_packed.shape[1] if ref_latents_packed is not None else 0) transformer_config = context.models.get_config(self.transformer.transformer) - # An nvfp4 or GGUF build dequantizes each packed Linear per forward, a transient its resident size does not - # cover. The cache holds back the larger of this and its default working memory, not their sum: this node has - # no activation estimate to add it to. Read from the unlocked model, before the lock; zero for every other - # build. - dequant_bytes = peak_dequant_transient_bytes(transformer_info.model, inference_dtype) + num_control_blocks = 0 + control_hidden_size = 0 + if control_branch_info is not None: + assert isinstance(control_branch_info.model, QwenImageFunControlBranch) + num_control_blocks = len(control_branch_info.model.control_blocks) + control_hidden_size = control_branch_info.model.hidden_size + # The forward's activations, which the cache keeps free by offloading as much of the transformer as that + # takes, plus the per-forward dequantization transient of an nvfp4 or GGUF build, alive alongside them and + # invisible to the estimate. All read from the unlocked model, before the lock; the transient is zero for a + # dense build. + text_seq_len = max( + pos_prompt_embeds.shape[1], neg_prompt_embeds.shape[1] if neg_prompt_embeds is not None else 0 + ) + working_mem_bytes = self._estimate_working_memory( + image_seq_len=model_input_seq_len, + text_seq_len=text_seq_len, + element_size=inference_dtype.itemsize, + num_control_blocks=num_control_blocks, + control_hidden_size=control_hidden_size, + ) + # Where SDPA has no fused kernel for the joint [text ; image] sequence (ROCm on Windows, MPS) it materializes + # the score matrices, which the linear term above was not priced for: 24 heads x 4608^2 scores is ~1 GB at + # 1024px with a 512-token prompt. A text mask, when the encoder emits one, narrows which fused kernels apply. + working_mem_bytes += self._attention_score_bytes( + transformer_info.model, + seq_len=model_input_seq_len + text_seq_len, + device=device, + dtype=inference_dtype, + has_attention_mask=pos_prompt_mask is not None or neg_prompt_mask is not None, + ) + working_mem_bytes += peak_dequant_transient_bytes(transformer_info.model, inference_dtype) + + # Encoded ahead of the transformer's lock, so the VAE does not have to fit beside it. + control_context: torch.Tensor | None = None + if control_branch_info is not None: + control_context = self._build_control_context(context, latent_height, latent_width) + control_context = control_context.to(device=device, dtype=inference_dtype) with ExitStack() as exit_stack: (cached_weights, transformer) = exit_stack.enter_context( - transformer_info.model_on_device(working_mem_bytes=dequant_bytes) + transformer_info.model_on_device(working_mem_bytes=working_mem_bytes) ) assert isinstance(transformer, QwenImageTransformer2DModel) + control_hooks: FunControlHooks | None = None + if control_branch_info is not None: + assert self.control is not None and control_context is not None + # Locked with the same working memory: the transformer can no longer be offloaded, so a branch placed + # with only the default reservation would fill the room kept for the forward. + (_, control_branch) = exit_stack.enter_context( + control_branch_info.model_on_device(working_mem_bytes=working_mem_bytes) + ) + assert isinstance(control_branch, QwenImageFunControlBranch) + # Dtype invariant: the loader cast the branch to the device's bfloat16-safe dtype, the policy the + # transformer loaders follow, which is `inference_dtype` wherever this node runs. Should the safe + # dtype ever be another one, the branch still runs its chain in its own dtype and casts every tensor + # on the way in and the hint on the way out (`QwenImageFunControlBranch.block_runner` / `add_hint`), + # so no cache-managed module is cast here. + control_hooks = exit_stack.enter_context( + install_fun_control( + transformer, control_branch, control_context, scale=self.control.control_context_scale + ) + ) # Quantized weights (packed nvfp4 Linears, GGUF, SDNQ) cannot take a direct patch, so their LoRAs ride as # sidecars. Asked of the loaded module tree: a `checkpoint` build may hold packed Linears. model_is_quantized = requires_sidecar_patching(transformer, transformer_config.format) @@ -489,6 +563,13 @@ def _run_diffusion(self, context: InvocationContext): exit_stack.enter_context(sage_attention_scope()) for step_idx, t in enumerate(tqdm(timesteps_sched)): + if control_hooks is not None: + assert self.control is not None + # One gate per step: both guidance branches run with the control, or neither does. + control_hooks.active = should_apply( + step_idx, total_steps, self.control.begin_step_percent, self.control.end_step_percent + ) + # The pipeline passes timestep / 1000 to the transformer timestep = t.expand(latents.shape[0]).to(inference_dtype) @@ -553,6 +634,112 @@ def _run_diffusion(self, context: InvocationContext): latents = latents.unsqueeze(2) return latents + def _load_control_branch(self, context: InvocationContext, has_zero_cond_t: bool) -> LoadedModel | None: + """The control branch in RAM, ahead of the transformer's lock so the reservation can size its hints.""" + if self.control is None: + return None + if self.vae is None: + raise ValueError( + "Qwen Image ControlNet needs the VAE that encodes its images: connect one to the 'vae' input." + ) + if self.reference_latents is not None: + raise ValueError("Qwen Image ControlNet cannot be combined with reference latents.") + # The Fun branch was trained beside the generation transformer. An Edit transformer takes a + # [noisy ; reference] sequence and modulates the two apart (zero_cond_t), a layout the branch never saw. + if has_zero_cond_t: + raise ValueError( + "Qwen Image ControlNet applies to the Qwen Image generation transformer, not to an Edit transformer." + ) + control_branch_info = context.models.load(self.control.control_model) + if not isinstance(control_branch_info.model, QwenImageFunControlBranch): + raise TypeError( + f"Expected a Qwen Image ControlNet for '{self.control.control_model.name}', " + f"got {type(control_branch_info.model).__name__}." + ) + return control_branch_info + + @staticmethod + def _estimate_working_memory( + image_seq_len: int, + text_seq_len: int, + element_size: int, + *, + num_control_blocks: int = 0, + control_hidden_size: int = 0, + ) -> int: + """Peak transformer activations, in bytes, for the model cache to keep free. + + Estimates pending calibration on this transformer. 0.25 MiB per token plus a 1 GiB base are the figures the + Qwen-Image-2.1 node reserves, measured there at 0.14 MiB per token in bf16 on an RTX 4090, with the margin + for the allocator. The per-token term is a bf16 figure and scales with `element_size`, the compute dtype's + width. The guidance branches run one after the other, so CFG adds nothing to the peak. + + A control branch runs its blocks over the image sequence and keeps one hint per block alive until the last + listed base layer has consumed it. `num_control_blocks + 4` hint-sized tensors is what Z-Image measured for + its adapter over the plain forward (`z_image_denoise.py`), pending the same measurement here. + """ + mib, gib = 1024**2, 1024**3 + width = element_size / 2 + estimated = int((image_seq_len + text_seq_len) * 0.25 * mib * width) + gib + if num_control_blocks: + estimated += (num_control_blocks + 4) * image_seq_len * control_hidden_size * element_size + return estimated + + @staticmethod + def _attention_score_bytes( + transformer: object, *, seq_len: int, device: torch.device, dtype: torch.dtype, has_attention_mask: bool + ) -> int: + """The score matrix attention materializes on a build without a fused kernel for it (0 where it has one). + + Every block attends the joint [text ; image] sequence once per forward through diffusers' attention dispatch; + the padding mask, when the encoder emits one, reaches the kernel as an additive mask. + """ + config = getattr(transformer, "config", None) + num_heads = getattr(config, "num_attention_heads", None) + head_dim = getattr(config, "attention_head_dim", None) + if not isinstance(num_heads, int) or not isinstance(head_dim, int): + return 0 + return sdpa_score_matrix_bytes( + device=device, + dtype=dtype, + num_heads=num_heads, + head_dim=head_dim, + seq_len=seq_len, + has_attn_mask=has_attention_mask, + via_diffusers_dispatch=True, + ) + + def _build_control_context(self, context: InvocationContext, latent_height: int, latent_width: int) -> torch.Tensor: + """The packed ``(1, S_img, 132)`` control context at the generation size, from the control field's images.""" + assert self.control is not None and self.vae is not None + control = self.control + vae_info = context.models.load(self.vae.vae) + tiled = control.tiled or context.config.get().force_tiled_decode + + def encode(pixels: torch.Tensor) -> torch.Tensor: + latents = QwenImageImageToLatentsInvocation.vae_encode( + vae_info=vae_info, image_tensor=pixels, tiled=tiled, tile_size=control.tile_size + ) + # The video-style VAE returns (B, C, 1, h, w); the context is one frame. + return latents.squeeze(2) + + def pixels(image_name: str, mode: str) -> torch.Tensor: + image = context.images.get_pil(image_name).convert(mode) + resample = Image.Resampling.LANCZOS if mode == "RGB" else Image.Resampling.BILINEAR + image = image.resize((self.width, self.height), resample) + # (1, C, H, W): pixels in [-1, 1], a mask in [0, 1]. + return image_resized_to_grid_as_tensor(image, normalize=mode == "RGB", multiple_of=16).unsqueeze(0) + + context_4d = build_qwen_image_control_context( + encode=encode, + control_image=pixels(control.image_name, "RGB") if control.image_name is not None else None, + inpaint_image=( + pixels(control.inpaint_image_name, "RGB") if control.inpaint_image_name is not None else None + ), + inpaint_mask=pixels(control.inpaint_mask_name, "L") if control.inpaint_mask_name is not None else None, + ) + return self._pack_latents(context_4d, 1, context_4d.shape[1], latent_height, latent_width) + def _build_step_callback(self, context: InvocationContext) -> Callable[[PipelineIntermediateState], None]: def step_callback(state: PipelineIntermediateState) -> None: context.util.sd_step_callback(state, BaseModelType.QwenImage) diff --git a/invokeai/backend/architectures/defs/qwen_image.py b/invokeai/backend/architectures/defs/qwen_image.py index 6f1f3758834..44dd5d5de88 100644 --- a/invokeai/backend/architectures/defs/qwen_image.py +++ b/invokeai/backend/architectures/defs/qwen_image.py @@ -31,6 +31,7 @@ dimension_grid=16, guidance_label="CFG", scheduler_set="standard", + control_kinds=frozenset({"qwen_image_control"}), max_reference_images=5, reference_images_require_variant="edit", ), diff --git a/invokeai/backend/architectures/facets/features.py b/invokeai/backend/architectures/facets/features.py index 0cae3669ef3..4c12a4b90f1 100644 --- a/invokeai/backend/architectures/facets/features.py +++ b/invokeai/backend/architectures/facets/features.py @@ -20,7 +20,11 @@ NegativePromptUsage = Literal["always", "cfg-gated", "never"] """`cfg-gated` means the field exists but only does anything above CFG 1 — the distilled models.""" -ControlKind = Literal["controlnet", "t2i_adapter", "control_lora", "z_image_control", "anima_lllite"] +ControlKind = Literal[ + "controlnet", "t2i_adapter", "control_lora", "z_image_control", "anima_lllite", "qwen_image_control" +] +"""A kind names the graph node webv2 compiles a control layer to, so an architecture with its own control node +is its own kind -- the Z-Image and Qwen-Image Fun branches are the same design and still two kinds.""" SchedulerSet = Literal["standard", "flow", "flow-no-lcm", "anima"] """Which family of schedulers to offer. `None` means the architecture drives its own and offers no diff --git a/invokeai/backend/fun_controlnet/__init__.py b/invokeai/backend/fun_controlnet/__init__.py new file mode 100644 index 00000000000..357a39cd731 --- /dev/null +++ b/invokeai/backend/fun_controlnet/__init__.py @@ -0,0 +1,8 @@ +"""Fun-style control branches (alibaba-pai VideoX-Fun), run beside a base transformer through forward hooks. + +Every Fun control model follows one recipe: the control context is projected to the block width, runs through a short +chain of blocks that are the base transformer's block plus two projections, and each block's ``after_proj`` output is +added to the base image stream after a listed base layer. ``branch.py`` holds the recipe and the seams a family fills +in, ``hooks.py`` attaches a branch to a transformer without touching its forward, and a module per family +(``qwen_image.py``) supplies the block class, the layer map and the calling convention. +""" diff --git a/invokeai/backend/fun_controlnet/branch.py b/invokeai/backend/fun_controlnet/branch.py new file mode 100644 index 00000000000..8717ad6d3c4 --- /dev/null +++ b/invokeai/backend/fun_controlnet/branch.py @@ -0,0 +1,84 @@ +from abc import ABC, abstractmethod +from collections.abc import Callable, Mapping, Sequence +from typing import Any + +import torch +from torch import nn + +BlockRunner = Callable[[nn.Module, torch.Tensor], torch.Tensor] +"""Runs one control block on the control image stream and returns the stream it produced. Whatever else the block +takes and updates (its own text stream, modulation, RoPE) the family closes over.""" + + +class FunControlBranch(nn.Module, ABC): + """``control_img_in`` and ``control_blocks``, with the base layers their hints land on. + + ``control_layers[k]`` is the index of the base block after whose output ``control_blocks[k]``'s hint is added. + Block 0 carries ``before_proj`` and every block ``after_proj``, both ``Linear(hidden, hidden)``; the family's block + class adds them to the base block it subclasses, and keeps that block's ``forward``. + + The abstract methods are the family seams the hooks go through: which base blocks to hook, how to read the base + image stream from block 0's arguments, how to call a control block with them, and where in a block's output the hint + goes. + """ + + def __init__( + self, control_img_in: nn.Linear, control_blocks: Sequence[nn.Module], control_layers: Sequence[int] + ) -> None: + super().__init__() + layers = tuple(control_layers) + if len(control_blocks) != len(layers) or not layers: + raise ValueError(f"{len(control_blocks)} control blocks for base layers {layers}: one block per layer.") + # The hooks drop the hints once the last listed layer has taken its share, which needs the layers in order. + if layers[0] < 0 or any(later <= earlier for earlier, later in zip(layers, layers[1:], strict=False)): + raise ValueError(f"Control layers must be non-negative and strictly increasing, got {layers}.") + self.control_img_in = control_img_in + self.control_blocks = nn.ModuleList(control_blocks) + self.control_layers = layers + + @property + def hidden_size(self) -> int: + return self.control_img_in.out_features + + @property + def control_in_dim(self) -> int: + return self.control_img_in.in_features + + @property + def dtype(self) -> torch.dtype: + return self.control_img_in.weight.dtype + + def compute_hints( + self, control_context: torch.Tensor, x: torch.Tensor, run_block: BlockRunner + ) -> list[torch.Tensor]: + """One hint per control block, from the control context and the base image stream ``x`` as it enters base + block 0. The chain runs in the branch's dtype; ``add_hint`` casts back.""" + c = self.control_img_in(control_context.to(self.dtype)) + hints: list[torch.Tensor] = [] + for index, block in enumerate(self.control_blocks): + if index == 0: + c = block.before_proj(c) + x.to(c.dtype) + c = run_block(block, c) + hints.append(block.after_proj(c)) + return hints + + @abstractmethod + def base_blocks(self, transformer: nn.Module) -> Sequence[nn.Module]: + """The base transformer's blocks, indexed as ``control_layers`` are.""" + + @abstractmethod + def base_hidden_size(self, transformer: nn.Module) -> int: + """The width of the base image stream the hints are added to.""" + + @abstractmethod + def image_stream(self, block_inputs: Mapping[str, Any]) -> torch.Tensor: + """The base image stream among base block 0's bound forward arguments.""" + + @abstractmethod + def block_runner(self, block_inputs: Mapping[str, Any]) -> BlockRunner: + """A runner that calls a control block the way the base called its block 0, threading the branch's own copy of + whatever else the block updates from call to call.""" + + @abstractmethod + def add_hint(self, output: Any, hint: torch.Tensor, scale: float) -> Any: + """A base block's ``output`` with ``hint * scale`` added to its image stream and nothing else touched.""" diff --git a/invokeai/backend/fun_controlnet/conditioning.py b/invokeai/backend/fun_controlnet/conditioning.py new file mode 100644 index 00000000000..73e9ae9d226 --- /dev/null +++ b/invokeai/backend/fun_controlnet/conditioning.py @@ -0,0 +1,61 @@ +from collections.abc import Callable + +import torch +import torch.nn.functional as F + +Encoder = Callable[[torch.Tensor], torch.Tensor] +"""Encodes pixels ``(1, 3, H, W)`` in [-1, 1] to the normalized latents ``(1, C, H/8, W/8)`` the denoise works in.""" + + +def build_qwen_image_control_context( + *, + encode: Encoder, + control_image: torch.Tensor | None = None, + inpaint_image: torch.Tensor | None = None, + inpaint_mask: torch.Tensor | None = None, +) -> torch.Tensor: + """The latent-space control context ``(1, 2C + 1, h, w)``: ``[control latents | keep mask | masked-image latents]``. + + VideoX-Fun ``pipeline_qwenimage_control.py``: the control image is encoded like the generation latents; the inpaint + mask ``(1, 1, H, W)`` in [0, 1] is thresholded at 0.5 (white is regenerated) and its complement nearest-sampled to + latent resolution as the keep mask, so the channel is exactly 0 or 1 even for a blurred mask; the inpaint image is + encoded with the regenerated pixels zeroed. Pure control leaves the inpaint channels at zero, pure inpaint the + control latents; the union checkpoint reads both. The denoise packs the result 2x2 the way it packs its latents. + """ + if (inpaint_image is None) != (inpaint_mask is None): + raise ValueError("An inpaint image and its mask go together.") + if control_image is None and inpaint_image is None: + raise ValueError("A control context needs a control image, an inpaint image with its mask, or both.") + + control_latents = encode(control_image) if control_image is not None else None + masked_latents = keep_mask = None + if inpaint_image is not None and inpaint_mask is not None: + if inpaint_mask.shape[-2:] != inpaint_image.shape[-2:]: + raise ValueError( + f"The inpaint mask {tuple(inpaint_mask.shape[-2:])} must be the size of the inpaint image " + f"{tuple(inpaint_image.shape[-2:])}." + ) + regenerate = inpaint_mask >= 0.5 + masked_latents = encode(inpaint_image * (~regenerate).to(inpaint_image.dtype)) + keep_mask = F.interpolate( + (~regenerate).to(device=masked_latents.device, dtype=masked_latents.dtype), + size=masked_latents.shape[-2:], + mode="nearest", + ) + if control_latents is not None and masked_latents is not None and control_latents.shape != masked_latents.shape: + raise ValueError( + f"The control image encodes to {tuple(control_latents.shape)} and the inpaint image to " + f"{tuple(masked_latents.shape)}; both must be the generation size." + ) + + reference = control_latents if control_latents is not None else masked_latents + assert reference is not None + batch, channels, height, width = reference.shape + return torch.cat( + [ + control_latents if control_latents is not None else reference.new_zeros((batch, channels, height, width)), + keep_mask if keep_mask is not None else reference.new_zeros((batch, 1, height, width)), + masked_latents if masked_latents is not None else reference.new_zeros((batch, channels, height, width)), + ], + dim=1, + ) diff --git a/invokeai/backend/fun_controlnet/hooks.py b/invokeai/backend/fun_controlnet/hooks.py new file mode 100644 index 00000000000..0f18378f414 --- /dev/null +++ b/invokeai/backend/fun_controlnet/hooks.py @@ -0,0 +1,110 @@ +import inspect +from collections.abc import Callable, Iterator, Sequence +from contextlib import contextmanager +from typing import Any + +import torch +from torch import nn +from torch.utils.hooks import RemovableHandle + +from invokeai.backend.fun_controlnet.branch import FunControlBranch + + +def should_apply(step_index: int, total_steps: int, begin_step_percent: float, end_step_percent: float) -> bool: + """Whether the control applies at a step: ``begin <= step_index / total_steps <= end``, both ends included, as the + Z-Image control extension counts.""" + if total_steps <= 0: + return True + return begin_step_percent <= step_index / total_steps <= end_step_percent + + +class FunControlHooks: + """The hooks a branch is installed with. ``active`` gates the forwards that follow without re-installing. + + Base block 0's pre-hook computes the hints from that forward's real arguments; the post-hook of each listed base + block adds its hint and the last one drops them, so no hint of one forward reaches the next and nothing stays alive + through the layers that come after the last listed one. + """ + + def __init__( + self, branch: FunControlBranch, blocks: Sequence[nn.Module], control_context: torch.Tensor, scale: float + ) -> None: + self.active = True + self._branch = branch + self._control_context = control_context + self._scale = scale + self._hints: list[torch.Tensor] | None = None + # Bound once: the base calls its blocks by keyword, a checkpointing caller by position, and the family reads + # the arguments by name either way. + self._signature = inspect.signature(blocks[0].forward) + last_layer = branch.control_layers[-1] + self._handles: list[RemovableHandle] = [ + blocks[0].register_forward_pre_hook(self._compute_hints, with_kwargs=True) + ] + for position, layer in enumerate(branch.control_layers): + self._handles.append( + blocks[layer].register_forward_hook(self._hint_adder(position, clear=layer == last_layer)) + ) + + def _compute_hints(self, _module: nn.Module, args: tuple[Any, ...], kwargs: dict[str, Any]) -> None: + # Block 0 runs first in every forward: whatever a previous forward left behind is stale here. + self._hints = None + if not self.active: + return None + bound = self._signature.bind(*args, **kwargs) + bound.apply_defaults() + inputs = bound.arguments + self._hints = self._branch.compute_hints( + self._control_context, self._branch.image_stream(inputs), self._branch.block_runner(inputs) + ) + return None + + def _hint_adder(self, position: int, clear: bool) -> Callable[[nn.Module, tuple[Any, ...], Any], Any]: + def add_hint(_module: nn.Module, _args: tuple[Any, ...], output: Any) -> Any: + if self._hints is None: + return None + hint = self._hints[position] + if clear: + self._hints = None + return self._branch.add_hint(output, hint, self._scale) + + return add_hint + + def remove(self) -> None: + for handle in self._handles: + handle.remove() + self._handles.clear() + self._hints = None + + +@contextmanager +def install_fun_control( + transformer: nn.Module, branch: FunControlBranch, control_context: torch.Tensor, *, scale: float +) -> Iterator[FunControlHooks]: + """Run ``transformer`` with ``branch``'s hints for the duration of the context. + + The hints are recomputed on every forward (each denoising step, each guidance branch) from the control context, + which is the same for both guidance branches. The hooks come off on exit however the body ends: the blocks belong to + the model cache and outlive this call. + """ + blocks = branch.base_blocks(transformer) + base_hidden_size = branch.base_hidden_size(transformer) + if base_hidden_size != branch.hidden_size: + raise ValueError( + f"The control branch is {branch.hidden_size} wide and the transformer {base_hidden_size}: " + "this is not a control model for this transformer." + ) + if len(blocks) <= branch.control_layers[-1]: + raise ValueError( + f"The control branch adds hints after base layers {branch.control_layers}; " + f"this transformer has {len(blocks)} blocks." + ) + if control_context.dim() != 3 or control_context.shape[-1] != branch.control_in_dim: + raise ValueError( + f"The control context must be (batch, tokens, {branch.control_in_dim}), got {tuple(control_context.shape)}." + ) + hooks = FunControlHooks(branch, blocks, control_context, scale) + try: + yield hooks + finally: + hooks.remove() diff --git a/invokeai/backend/fun_controlnet/qwen_image.py b/invokeai/backend/fun_controlnet/qwen_image.py new file mode 100644 index 00000000000..df8d5685a1b --- /dev/null +++ b/invokeai/backend/fun_controlnet/qwen_image.py @@ -0,0 +1,157 @@ +"""Qwen-Image Fun-ControlNet-Union: the control branch alibaba-pai trained for the Qwen-Image generation transformer. + +Reference: VideoX-Fun ``videox_fun/models/qwenimage_transformer2d_control.py`` and +``pipeline_qwenimage_control.py``; ComfyUI mirrors it in ``comfy/ldm/qwen_image/controlnet.py``. +""" + +from collections.abc import Mapping, Sequence +from typing import Any + +import accelerate +import torch +from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformerBlock +from torch import nn + +from invokeai.backend.fun_controlnet.branch import BlockRunner, FunControlBranch + +# VideoX-Fun `config/qwenimage/qwenimage_control.yaml`: five control blocks, their hints added after these base +# blocks. The checkpoint carries no config, so the map is a constant of the family. +QWEN_IMAGE_FUN_CONTROL_LAYERS: tuple[int, ...] = (0, 12, 24, 36, 48) +# 33 latent channels -- control latents (16), inpaint keep mask (1), masked-image latents (16) -- packed 2x2. +QWEN_IMAGE_FUN_CONTROL_IN_DIM = 132 +# Qwen-Image attention heads are 128 wide. The checkpoint does not say, so the head count follows from the width. +QWEN_IMAGE_ATTENTION_HEAD_DIM = 128 + +_IMAGE_STREAM = "hidden_states" +_TEXT_STREAM = "encoder_hidden_states" + + +class QwenImageFunControlBlock(QwenImageTransformerBlock): + """A Qwen-Image block plus the two projections of the control recipe; ``forward`` is the base block's.""" + + def __init__(self, *, dim: int, num_attention_heads: int, attention_head_dim: int, first: bool) -> None: + super().__init__(dim=dim, num_attention_heads=num_attention_heads, attention_head_dim=attention_head_dim) + if first: + self.before_proj = nn.Linear(dim, dim) + self.after_proj = nn.Linear(dim, dim) + + +class QwenImageFunControlBranch(FunControlBranch): + """The branch for ``QwenImageTransformer2DModel``: control blocks thread their own text stream beside the base's. + + The hint is added to the image stream only. ``modulate_index`` and ``zero_cond_t`` belong to the Edit transformer, + which the checkpoint was not trained on; the denoise refuses that pairing before anything is installed. + """ + + def __init__( + self, + *, + hidden_size: int, + num_attention_heads: int, + attention_head_dim: int, + control_in_dim: int = QWEN_IMAGE_FUN_CONTROL_IN_DIM, + control_layers: Sequence[int] = QWEN_IMAGE_FUN_CONTROL_LAYERS, + ) -> None: + blocks = [ + QwenImageFunControlBlock( + dim=hidden_size, + num_attention_heads=num_attention_heads, + attention_head_dim=attention_head_dim, + first=index == 0, + ) + for index in range(len(control_layers)) + ] + super().__init__(nn.Linear(control_in_dim, hidden_size), blocks, control_layers) + + @classmethod + def from_state_dict( + cls, + sd: Mapping[str, torch.Tensor], + *, + dtype: torch.dtype, + control_layers: Sequence[int] = QWEN_IMAGE_FUN_CONTROL_LAYERS, + attention_head_dim: int = QWEN_IMAGE_ATTENTION_HEAD_DIM, + ) -> "QwenImageFunControlBranch": + """Build the branch the checkpoint describes and load it, cast to ``dtype``. + + The geometry is read off the tensors: the width and input features from ``control_img_in.weight``, the block + count from the highest ``control_blocks.N`` index. Anything that is not the Qwen-Image recipe is refused by + name rather than loaded into a branch that would run and produce noise. + """ + weight = sd.get("control_img_in.weight") + if weight is None or weight.dim() != 2: + raise ValueError("Not a Qwen Image Fun-ControlNet checkpoint: `control_img_in.weight` is missing.") + hidden_size, control_in_dim = weight.shape + if control_in_dim != QWEN_IMAGE_FUN_CONTROL_IN_DIM: + raise ValueError( + f"Qwen Image Fun-ControlNet takes {QWEN_IMAGE_FUN_CONTROL_IN_DIM} control features per token (33 latent " + f"channels packed 2x2); this checkpoint's `control_img_in` takes {control_in_dim}." + ) + if hidden_size % attention_head_dim: + raise ValueError( + f"A {hidden_size}-wide branch cannot be split into {attention_head_dim}-wide attention heads." + ) + layers = tuple(control_layers) + block_indices = { + int(parts[1]) + for key in sd + if (parts := key.split(".")) and parts[0] == "control_blocks" and parts[1].isdigit() + } + num_blocks = max(block_indices, default=-1) + 1 + if num_blocks != len(layers): + raise ValueError( + f"This checkpoint has {num_blocks} control blocks; the Qwen Image recipe places {len(layers)} after base " + f"layers {layers}." + ) + + with accelerate.init_empty_weights(): + branch = cls( + hidden_size=hidden_size, + num_attention_heads=hidden_size // attention_head_dim, + attention_head_dim=attention_head_dim, + control_in_dim=control_in_dim, + control_layers=layers, + ) + missing, unexpected = branch.load_state_dict(dict(sd), strict=False, assign=True) + if missing or unexpected: + raise ValueError( + "This checkpoint does not match the Qwen Image control block layout: " + f"missing {sorted(missing)[:5]}, unexpected {sorted(unexpected)[:5]}." + ) + return branch.to(dtype=dtype).eval() + + def base_blocks(self, transformer: nn.Module) -> Sequence[nn.Module]: + return transformer.transformer_blocks + + def base_hidden_size(self, transformer: nn.Module) -> int: + return transformer.inner_dim + + def image_stream(self, block_inputs: Mapping[str, Any]) -> torch.Tensor: + return block_inputs[_IMAGE_STREAM] + + def block_runner(self, block_inputs: Mapping[str, Any]) -> BlockRunner: + # Mask, modulation input, RoPE, attention kwargs: the control blocks take exactly what the base block took. + # VideoX-Fun hands the base's `encoder_hidden_states_mask` to the control blocks; ComfyUI's mirror forces it to + # None. Both agree whenever every text token is valid, which is when Invoke's encoder passes None, so the + # VideoX reading is kept here -- do not "fix" it toward ComfyUI. + # The chain runs in the branch's dtype end to end: the floating inputs (the modulation input) are cast on the + # way in, like `c` and the text stream, and the hint on the way out (`add_hint`). RoPE is complex and the mask + # boolean; neither is touched. + passthrough = { + name: value.to(self.dtype) if isinstance(value, torch.Tensor) and value.is_floating_point() else value + for name, value in block_inputs.items() + if name not in (_IMAGE_STREAM, _TEXT_STREAM) + } + # The chain starts from the base's text stream as it enters block 0 and carries its own copy from then on. + text_stream = block_inputs[_TEXT_STREAM].to(self.dtype) + + def run(block: nn.Module, c: torch.Tensor) -> torch.Tensor: + nonlocal text_stream + text_stream, c = block(hidden_states=c, encoder_hidden_states=text_stream, **passthrough) + return c + + return run + + def add_hint(self, output: Any, hint: torch.Tensor, scale: float) -> Any: + encoder_hidden_states, hidden_states = output + return encoder_hidden_states, hidden_states + (hint * scale).to(hidden_states.dtype) diff --git a/invokeai/backend/model_manager/configs/controlnet.py b/invokeai/backend/model_manager/configs/controlnet.py index 890172e00fb..2a3ab146b16 100644 --- a/invokeai/backend/model_manager/configs/controlnet.py +++ b/invokeai/backend/model_manager/configs/controlnet.py @@ -280,6 +280,54 @@ def _validate_looks_like_z_image_control(cls, mod: ModelOnDisk) -> None: raise NotAMatchError("state dict does not look like a Z-Image Control model") +# `control_img_in` takes 132 packed channels into Qwen-Image's 3072-wide stream. The Qwen-Image-2.1 Fun branch +# takes 129 into 4096 and the FLUX.2 one 260 into 6144, so the shape alone tells the three apart. +_QWEN_IMAGE_FUN_CONTROL_IMG_IN_SHAPE = (3072, 132) + + +def _has_qwen_image_fun_control_keys(state_dict: dict) -> bool: + """Check if state dict is a Qwen-Image Fun-ControlNet branch (alibaba-pai's VACE-style union adapter). + + The branch is `control_img_in` plus `control_blocks.N`, copies of Qwen-Image's dual-stream + `QwenImageTransformerBlock` with `before_proj`/`after_proj` taps. Its siblings reuse the naming, so the + fingerprint is the projection shape and the dual-stream `img_mod`, which the single-stream Qwen-Image-2.1 + branch lacks. + """ + control_img_in = state_dict.get("control_img_in.weight") + shape = getattr(control_img_in, "shape", None) + if shape is None or tuple(shape) != _QWEN_IMAGE_FUN_CONTROL_IMG_IN_SHAPE: + return False + return "control_blocks.0.img_mod.1.weight" in state_dict + + +class ControlNet_Checkpoint_QwenImage_Config(Checkpoint_Config_Base, Config_Base): + """Model config for Qwen-Image Fun-ControlNet adapter models (Safetensors checkpoint). + + Qwen-Image Fun-ControlNets are standalone adapters containing only the control branch + (control_img_in, control_blocks) that extends the base Qwen-Image transformer with spatial + conditioning capabilities. + + Supports: Canny, HED, Depth, Pose, MLSD, Scribble, Gray, inpainting. + Recommended control_context_scale: 0.70-0.95. + """ + + type: Literal[ModelType.ControlNet] = Field(default=ModelType.ControlNet) + format: Literal[ModelFormat.Checkpoint] = Field(default=ModelFormat.Checkpoint) + base: Literal[BaseModelType.QwenImage] = Field(default=BaseModelType.QwenImage) + default_settings: ControlAdapterDefaultSettings | None = Field(None) + + @classmethod + def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) -> Self: + raise_if_not_file(mod) + + raise_for_override_fields(cls, override_fields) + + if not _has_qwen_image_fun_control_keys(mod.load_state_dict()): + raise NotAMatchError("state dict does not look like a Qwen-Image Fun-ControlNet") + + return cls(**override_fields) + + def _has_anima_lllite_keys(state_dict: dict) -> bool: """Check if state dict contains Anima ControlNet-LLLite specific keys. diff --git a/invokeai/backend/model_manager/configs/factory.py b/invokeai/backend/model_manager/configs/factory.py index 27553c2200c..d42fbb1ff08 100644 --- a/invokeai/backend/model_manager/configs/factory.py +++ b/invokeai/backend/model_manager/configs/factory.py @@ -26,6 +26,7 @@ ControlAdapterDefaultSettings, ControlNet_Checkpoint_Anima_Config, ControlNet_Checkpoint_FLUX_Config, + ControlNet_Checkpoint_QwenImage_Config, ControlNet_Checkpoint_SD1_Config, ControlNet_Checkpoint_SD2_Config, ControlNet_Checkpoint_SDXL_Config, @@ -493,6 +494,7 @@ def has_model_export(module: Any, name: Any, expected_bases: tuple[type, ...]) - Annotated[ControlNet_Checkpoint_FLUX_Config, ControlNet_Checkpoint_FLUX_Config.get_tag()], Annotated[ControlNet_Checkpoint_ZImage_Config, ControlNet_Checkpoint_ZImage_Config.get_tag()], Annotated[ControlNet_Checkpoint_Anima_Config, ControlNet_Checkpoint_Anima_Config.get_tag()], + Annotated[ControlNet_Checkpoint_QwenImage_Config, ControlNet_Checkpoint_QwenImage_Config.get_tag()], # ControlNet - diffusers format Annotated[ControlNet_Diffusers_SD1_Config, ControlNet_Diffusers_SD1_Config.get_tag()], Annotated[ControlNet_Diffusers_SD2_Config, ControlNet_Diffusers_SD2_Config.get_tag()], diff --git a/invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py b/invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py new file mode 100644 index 00000000000..da58d7b2521 --- /dev/null +++ b/invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py @@ -0,0 +1,44 @@ +"""Loaders for Fun-ControlNet branches (alibaba-pai VideoX-Fun); today the Qwen-Image Fun-ControlNet-Union.""" + +from pathlib import Path +from typing import Optional + +from safetensors.torch import load_file + +from invokeai.backend.fun_controlnet.qwen_image import QwenImageFunControlBranch +from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base +from invokeai.backend.model_manager.configs.factory import AnyModelConfig +from invokeai.backend.model_manager.load.fp8_capability import Unimplemented +from invokeai.backend.model_manager.load.load_default import ModelLoader +from invokeai.backend.model_manager.load.model_loader_registry import ModelLoaderRegistry +from invokeai.backend.model_manager.taxonomy import AnyModel, BaseModelType, ModelFormat, ModelType, SubModelType +from invokeai.backend.quantization.fp8_scaled import reject_quantized_side_channel +from invokeai.backend.util.devices import TorchDevice + + +@ModelLoaderRegistry.register( + base=BaseModelType.QwenImage, + type=ModelType.ControlNet, + format=ModelFormat.Checkpoint, + fp8_storage=Unimplemented( + "the branch is cast to the compute dtype at load and runs as its own module tree, so the layerwise cast would " + "fit; at 3.5 GB in bf16 it is worth closing" + ), +) +class QwenImageFunControlNetLoader(ModelLoader): + """Loads the Qwen-Image Fun-ControlNet-Union branch from its safetensors file. + + The file carries no config: the branch's geometry is read off its tensors and the base-layer map is the family's + constant (`QWEN_IMAGE_FUN_CONTROL_LAYERS`). + """ + + def _load_model(self, config: AnyModelConfig, submodel_type: Optional[SubModelType] = None) -> AnyModel: + path = Path(config.path) + if not isinstance(config, Checkpoint_Config_Base): + raise ValueError("Only checkpoint configs are supported here.") + sd = load_file(path) + # Before the geometry probe: the shapes it reads mean nothing on a packed weight, and no scale is folded here. + reject_quantized_side_channel(sd, f"Qwen Image ControlNet checkpoint {path.name}") + return QwenImageFunControlBranch.from_state_dict( + sd, dtype=TorchDevice.choose_bfloat16_safe_dtype(self._torch_device) + ) diff --git a/invokeai/backend/model_manager/starter_models/__init__.py b/invokeai/backend/model_manager/starter_models/__init__.py index a7b2a814a04..866181eb078 100644 --- a/invokeai/backend/model_manager/starter_models/__init__.py +++ b/invokeai/backend/model_manager/starter_models/__init__.py @@ -208,6 +208,7 @@ qwen_image_edit_gguf_q8_0, qwen_image_edit_lightning_4step, qwen_image_edit_lightning_8step, + qwen_image_fun_controlnet_union, qwen_image_gguf_q2_k, qwen_image_gguf_q4_k_m, qwen_image_gguf_q6_k, @@ -461,6 +462,7 @@ qwen_image_gguf_q8_0, qwen_image_lightning_4step, qwen_image_lightning_8step, + qwen_image_fun_controlnet_union, flux_krea, flux_krea_quantized, z_image_turbo, @@ -681,6 +683,7 @@ qwen_image_gguf_q8_0, qwen_image_lightning_4step, qwen_image_lightning_8step, + qwen_image_fun_controlnet_union, ] anima_bundle: list[StarterModel] = [ diff --git a/invokeai/backend/model_manager/starter_models/qwen_image.py b/invokeai/backend/model_manager/starter_models/qwen_image.py index fcdbab05aca..028be0b828c 100644 --- a/invokeai/backend/model_manager/starter_models/qwen_image.py +++ b/invokeai/backend/model_manager/starter_models/qwen_image.py @@ -196,3 +196,13 @@ "Settings: Steps=8, CFG=1, Shift Override=3.", type=ModelType.LoRA, ) + +# region Qwen Image ControlNet +qwen_image_fun_controlnet_union = StarterModel( + name="Qwen Image ControlNet Union", + base=BaseModelType.QwenImage, + source="https://huggingface.co/alibaba-pai/Qwen-Image-2512-Fun-Controlnet-Union/resolve/main/Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors", + description="Unified ControlNet for Qwen Image 2512 supporting Canny, HED, Depth, Pose, MLSD, Scribble and Gray " + "control images, plus inpainting. Works best at weights 0.70-0.95. Apache-2.0. ~3.5GB", + type=ModelType.ControlNet, +) diff --git a/invokeai/frontend/api/openapi.json b/invokeai/frontend/api/openapi.json index 683424ebbfb..c929139d5cb 100644 --- a/invokeai/frontend/api/openapi.json +++ b/invokeai/frontend/api/openapi.json @@ -1601,6 +1601,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -2098,6 +2101,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -2595,6 +2601,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -3137,6 +3146,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -3706,6 +3718,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -5147,6 +5162,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -19832,6 +19850,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -20413,7 +20434,14 @@ "control_kinds": { "items": { "type": "string", - "enum": ["controlnet", "t2i_adapter", "control_lora", "z_image_control", "anima_lllite"] + "enum": [ + "controlnet", + "t2i_adapter", + "control_lora", + "z_image_control", + "anima_lllite", + "qwen_image_control" + ] }, "type": "array", "title": "Control Kinds", @@ -27678,6 +27706,153 @@ ], "title": "ControlNet_Checkpoint_FLUX_Config" }, + "ControlNet_Checkpoint_QwenImage_Config": { + "properties": { + "key": { + "type": "string", + "title": "Key", + "description": "A unique key for this model." + }, + "hash": { + "type": "string", + "title": "Hash", + "description": "The hash of the model file(s)." + }, + "path": { + "type": "string", + "title": "Path", + "description": "Path to the model on the filesystem. Relative paths are relative to the Invoke root directory." + }, + "file_size": { + "type": "integer", + "title": "File Size", + "description": "The size of the model in bytes." + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the model." + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description", + "description": "Model description" + }, + "source": { + "type": "string", + "title": "Source", + "description": "The original source of the model (path, URL or repo_id)." + }, + "source_type": { + "$ref": "#/components/schemas/ModelSourceType", + "description": "The type of source" + }, + "source_api_response": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Source Api Response", + "description": "The original API response from the source, as stringified JSON." + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Source Url", + "description": "Optional URL for the model (e.g. download page or model page)." + }, + "cover_image": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cover Image", + "description": "Url for image to preview model" + }, + "config_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Config Path", + "description": "Path to the config for this model, if any." + }, + "type": { + "type": "string", + "const": "controlnet", + "title": "Type", + "default": "controlnet" + }, + "format": { + "type": "string", + "const": "checkpoint", + "title": "Format", + "default": "checkpoint" + }, + "base": { + "type": "string", + "const": "qwen-image", + "title": "Base", + "default": "qwen-image" + }, + "default_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/ControlAdapterDefaultSettings" + }, + { + "type": "null" + } + ] + } + }, + "type": "object", + "required": [ + "key", + "hash", + "path", + "file_size", + "name", + "description", + "source", + "source_type", + "source_api_response", + "source_url", + "cover_image", + "config_path", + "type", + "format", + "base", + "default_settings" + ], + "title": "ControlNet_Checkpoint_QwenImage_Config", + "description": "Model config for Qwen-Image Fun-ControlNet adapter models (Safetensors checkpoint).\n\nQwen-Image Fun-ControlNets are standalone adapters containing only the control branch\n(control_img_in, control_blocks) that extends the base Qwen-Image transformer with spatial\nconditioning capabilities.\n\nSupports: Canny, HED, Depth, Pose, MLSD, Scribble, Gray, inpainting.\nRecommended control_context_scale: 0.70-0.95." + }, "ControlNet_Checkpoint_SD1_Config": { "properties": { "key": { @@ -43685,6 +43860,9 @@ { "$ref": "#/components/schemas/QwenImage21TextEncoderInvocation" }, + { + "$ref": "#/components/schemas/QwenImageControlInvocation" + }, { "$ref": "#/components/schemas/QwenImageDenoiseInvocation" }, @@ -44342,6 +44520,9 @@ { "$ref": "#/components/schemas/QwenImageConditioningOutput" }, + { + "$ref": "#/components/schemas/QwenImageControlOutput" + }, { "$ref": "#/components/schemas/QwenImageLoRALoaderOutput" }, @@ -53985,6 +54166,9 @@ { "$ref": "#/components/schemas/QwenImage21TextEncoderInvocation" }, + { + "$ref": "#/components/schemas/QwenImageControlInvocation" + }, { "$ref": "#/components/schemas/QwenImageDenoiseInvocation" }, @@ -54638,6 +54822,9 @@ { "$ref": "#/components/schemas/QwenImageConditioningOutput" }, + { + "$ref": "#/components/schemas/QwenImageControlOutput" + }, { "$ref": "#/components/schemas/QwenImageLoRALoaderOutput" }, @@ -55600,6 +55787,9 @@ { "$ref": "#/components/schemas/QwenImage21TextEncoderInvocation" }, + { + "$ref": "#/components/schemas/QwenImageControlInvocation" + }, { "$ref": "#/components/schemas/QwenImageDenoiseInvocation" }, @@ -56737,6 +56927,9 @@ "qwen_image_2_1_text_encoder": { "$ref": "#/components/schemas/QwenImage21ConditioningOutput" }, + "qwen_image_control": { + "$ref": "#/components/schemas/QwenImageControlOutput" + }, "qwen_image_denoise": { "$ref": "#/components/schemas/LatentsOutput" }, @@ -57270,6 +57463,7 @@ "qwen_image_2_1_l2i", "qwen_image_2_1_model_loader", "qwen_image_2_1_text_encoder", + "qwen_image_control", "qwen_image_denoise", "qwen_image_i2l", "qwen_image_l2i", @@ -58211,6 +58405,9 @@ { "$ref": "#/components/schemas/QwenImage21TextEncoderInvocation" }, + { + "$ref": "#/components/schemas/QwenImageControlInvocation" + }, { "$ref": "#/components/schemas/QwenImageDenoiseInvocation" }, @@ -59456,6 +59653,9 @@ { "$ref": "#/components/schemas/QwenImage21TextEncoderInvocation" }, + { + "$ref": "#/components/schemas/QwenImageControlInvocation" + }, { "$ref": "#/components/schemas/QwenImageDenoiseInvocation" }, @@ -86411,6 +86611,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -87154,6 +87357,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -87782,6 +87988,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -88266,6 +88475,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -89243,6 +89455,9 @@ { "$ref": "#/components/schemas/ControlNet_Checkpoint_Anima_Config" }, + { + "$ref": "#/components/schemas/ControlNet_Checkpoint_QwenImage_Config" + }, { "$ref": "#/components/schemas/ControlNet_Diffusers_SD1_Config" }, @@ -95593,6 +95808,289 @@ "title": "QwenImageConditioningOutput", "type": "object" }, + "QwenImageControlField": { + "description": "Qwen Image Fun-ControlNet conditioning: a control image, an inpaint image with its mask, or both.", + "properties": { + "image_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The preprocessed control image (Canny, depth, pose, ...)", + "title": "Image Name" + }, + "inpaint_image_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The image to inpaint", + "title": "Inpaint Image Name" + }, + "inpaint_mask_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The inpaint mask; white is regenerated", + "title": "Inpaint Mask Name" + }, + "control_model": { + "$ref": "#/components/schemas/ModelIdentifierField", + "description": "The Qwen Image ControlNet model" + }, + "control_context_scale": { + "default": 0.85, + "description": "Strength of the control signal. Recommended range: 0.70-0.95.", + "maximum": 2.0, + "minimum": 0.0, + "title": "Control Context Scale", + "type": "number" + }, + "begin_step_percent": { + "default": 0.0, + "description": "When the control is first applied (% of total steps)", + "maximum": 1.0, + "minimum": 0.0, + "title": "Begin Step Percent", + "type": "number" + }, + "end_step_percent": { + "default": 1.0, + "description": "When the control is last applied (% of total steps)", + "maximum": 1.0, + "minimum": 0.0, + "title": "End Step Percent", + "type": "number" + }, + "tiled": { + "default": false, + "description": "Encode the control images in tiles. The denoise encodes them at generation size, which for an upscale is the enlarged frame -- too large for an untiled encode on consumer hardware.", + "title": "Tiled", + "type": "boolean" + }, + "tile_size": { + "default": 0, + "description": "The tile size for VAE tiling in pixels (image space). If set to 0, the default tile size for the model will be used. Larger tile sizes generally produce better results at the cost of higher memory usage. Values between 1 and 64 are raised to 64.", + "minimum": 0, + "multipleOf": 8, + "title": "Tile Size", + "type": "integer" + } + }, + "required": ["control_model"], + "title": "QwenImageControlField", + "type": "object" + }, + "QwenImageControlInvocation": { + "category": "conditioning", + "class": "invocation", + "classification": "prototype", + "description": "Configure the Qwen Image Fun-ControlNet-Union for spatial control, inpainting, or both.\n\nTakes a preprocessed control image (Canny, HED, depth, pose, MLSD, ...) and/or an image to inpaint with its mask\n(white is regenerated), plus the Qwen Image ControlNet model. Recommended control scale: 0.70-0.95.", + "node_pack": "invokeai", + "properties": { + "id": { + "description": "The id of this instance of an invocation. Must be unique among all instances of invocations.", + "field_kind": "node_attribute", + "title": "Id", + "type": "string" + }, + "is_intermediate": { + "default": false, + "description": "Whether or not this is an intermediate invocation.", + "field_kind": "node_attribute", + "input": "direct", + "orig_required": true, + "title": "Is Intermediate", + "type": "boolean", + "ui_hidden": false, + "ui_type": "IsIntermediate" + }, + "use_cache": { + "default": true, + "description": "Whether or not to use the cache", + "field_kind": "node_attribute", + "title": "Use Cache", + "type": "boolean" + }, + "image": { + "anyOf": [ + { + "$ref": "#/components/schemas/ImageField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The preprocessed control image (Canny, HED, depth, pose, MLSD, ...)", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "inpaint_image": { + "anyOf": [ + { + "$ref": "#/components/schemas/ImageField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The image to inpaint. Goes together with the inpaint mask.", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "inpaint_mask": { + "anyOf": [ + { + "$ref": "#/components/schemas/ImageField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The inpaint mask: white is regenerated, black is kept. Goes together with the inpaint image.", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "control_model": { + "anyOf": [ + { + "$ref": "#/components/schemas/ModelIdentifierField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "ControlNet model to load", + "field_kind": "input", + "input": "any", + "orig_required": true, + "title": "Control Model", + "ui_model_base": ["qwen-image"], + "ui_model_type": ["controlnet"] + }, + "control_context_scale": { + "default": 0.85, + "description": "Strength of the control signal. Recommended range: 0.70-0.95.", + "field_kind": "input", + "input": "any", + "maximum": 2.0, + "minimum": 0.0, + "orig_default": 0.85, + "orig_required": false, + "title": "Control Scale", + "type": "number" + }, + "begin_step_percent": { + "default": 0.0, + "description": "When the control is first applied (% of total steps)", + "field_kind": "input", + "input": "any", + "maximum": 1.0, + "minimum": 0.0, + "orig_default": 0.0, + "orig_required": false, + "title": "Begin Step Percent", + "type": "number" + }, + "end_step_percent": { + "default": 1.0, + "description": "When the control is last applied (% of total steps)", + "field_kind": "input", + "input": "any", + "maximum": 1.0, + "minimum": 0.0, + "orig_default": 1.0, + "orig_required": false, + "title": "End Step Percent", + "type": "number" + }, + "tiled": { + "default": false, + "description": "Processing using overlapping tiles (reduce memory consumption)", + "field_kind": "input", + "input": "any", + "orig_default": false, + "orig_required": false, + "title": "Tiled", + "type": "boolean" + }, + "tile_size": { + "default": 0, + "description": "The tile size for VAE tiling in pixels (image space). If set to 0, the default tile size for the model will be used. Larger tile sizes generally produce better results at the cost of higher memory usage. Values between 1 and 64 are raised to 64.", + "field_kind": "input", + "input": "any", + "minimum": 0, + "multipleOf": 8, + "orig_default": 0, + "orig_required": false, + "title": "Tile Size", + "type": "integer" + }, + "type": { + "const": "qwen_image_control", + "default": "qwen_image_control", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["image", "qwen_image", "control", "controlnet", "inpaint"], + "title": "Qwen Image ControlNet", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/QwenImageControlOutput" + } + }, + "QwenImageControlOutput": { + "class": "output", + "description": "Qwen Image Control output containing control configuration.", + "properties": { + "control": { + "$ref": "#/components/schemas/QwenImageControlField", + "description": "Qwen Image control conditioning", + "field_kind": "output", + "ui_hidden": false + }, + "type": { + "const": "qwen_image_control_output", + "default": "qwen_image_control_output", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["output_meta", "control", "type", "type"], + "title": "QwenImageControlOutput", + "type": "object" + }, "QwenImageDenoiseInvocation": { "category": "image", "class": "invocation", @@ -95855,6 +96353,38 @@ "orig_required": false, "title": "Shift" }, + "control": { + "anyOf": [ + { + "$ref": "#/components/schemas/QwenImageControlField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Qwen Image ControlNet conditioning: spatial control (Canny, depth, pose, ...) and/or inpainting.", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false + }, + "vae": { + "anyOf": [ + { + "$ref": "#/components/schemas/VAEField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "VAE Required for control conditioning.", + "field_kind": "input", + "input": "connection", + "orig_default": null, + "orig_required": false + }, "type": { "const": "qwen_image_denoise", "default": "qwen_image_denoise", @@ -95867,7 +96397,7 @@ "tags": ["image", "qwen_image"], "title": "Denoise - Qwen Image", "type": "object", - "version": "1.0.0", + "version": "1.1.0", "output": { "$ref": "#/components/schemas/LatentsOutput" } diff --git a/invokeai/frontend/api/schema.ts b/invokeai/frontend/api/schema.ts index 5e8cb075413..036c3893488 100644 --- a/invokeai/frontend/api/schema.ts +++ b/invokeai/frontend/api/schema.ts @@ -5535,7 +5535,7 @@ export type components = { * @enum {string} */ AnimaVariantType: "anima_qwen3" | "anima_qwen35"; - AnyModelConfig: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + AnyModelConfig: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; /** * AppVersion * @description App Version Response @@ -5717,7 +5717,7 @@ export type components = { * Control Kinds * @description Sorted. */ - control_kinds?: ("controlnet" | "t2i_adapter" | "control_lora" | "z_image_control" | "anima_lllite")[]; + control_kinds?: ("controlnet" | "t2i_adapter" | "control_lora" | "z_image_control" | "anima_lllite" | "qwen_image_control")[]; /** * Max Reference Images * @default 0 @@ -9736,6 +9736,95 @@ export type components = { */ base: "flux"; }; + /** + * ControlNet_Checkpoint_QwenImage_Config + * @description Model config for Qwen-Image Fun-ControlNet adapter models (Safetensors checkpoint). + * + * Qwen-Image Fun-ControlNets are standalone adapters containing only the control branch + * (control_img_in, control_blocks) that extends the base Qwen-Image transformer with spatial + * conditioning capabilities. + * + * Supports: Canny, HED, Depth, Pose, MLSD, Scribble, Gray, inpainting. + * Recommended control_context_scale: 0.70-0.95. + */ + ControlNet_Checkpoint_QwenImage_Config: { + /** + * Key + * @description A unique key for this model. + */ + key: string; + /** + * Hash + * @description The hash of the model file(s). + */ + hash: string; + /** + * Path + * @description Path to the model on the filesystem. Relative paths are relative to the Invoke root directory. + */ + path: string; + /** + * File Size + * @description The size of the model in bytes. + */ + file_size: number; + /** + * Name + * @description Name of the model. + */ + name: string; + /** + * Description + * @description Model description + */ + description: string | null; + /** + * Source + * @description The original source of the model (path, URL or repo_id). + */ + source: string; + /** @description The type of source */ + source_type: components["schemas"]["ModelSourceType"]; + /** + * Source Api Response + * @description The original API response from the source, as stringified JSON. + */ + source_api_response: string | null; + /** + * Source Url + * @description Optional URL for the model (e.g. download page or model page). + */ + source_url: string | null; + /** + * Cover Image + * @description Url for image to preview model + */ + cover_image: string | null; + /** + * Config Path + * @description Path to the config for this model, if any. + */ + config_path: string | null; + /** + * Type + * @default controlnet + * @constant + */ + type: "controlnet"; + /** + * Format + * @default checkpoint + * @constant + */ + format: "checkpoint"; + /** + * Base + * @default qwen-image + * @constant + */ + base: "qwen-image"; + default_settings: components["schemas"]["ControlAdapterDefaultSettings"] | null; + }; /** ControlNet_Checkpoint_SD1_Config */ ControlNet_Checkpoint_SD1_Config: { /** @@ -17331,7 +17420,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageControlInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; }; /** * Edges @@ -17368,7 +17457,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["AnimaConditioningOutput"] | components["schemas"]["AnimaLLLiteOutput"] | components["schemas"]["AnimaLoRALoaderOutput"] | components["schemas"]["AnimaModelLoaderOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["BoundingBoxCollectionOutput"] | components["schemas"]["BoundingBoxOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["CogView4ConditioningOutput"] | components["schemas"]["CogView4ModelLoaderOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["CollectionCartesianInvocationOutput"] | components["schemas"]["CollectionConcatInvocationOutput"] | components["schemas"]["CollectionZipInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ErnieImageConditioningOutput"] | components["schemas"]["ErnieImageModelLoaderOutput"] | components["schemas"]["ExtractVideoRangeOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["Flux2DevLoRALoaderOutput"] | components["schemas"]["Flux2DevModelLoaderOutput"] | components["schemas"]["Flux2KleinLoRALoaderOutput"] | components["schemas"]["Flux2KleinModelLoaderOutput"] | components["schemas"]["FluxConditioningCollectionOutput"] | components["schemas"]["FluxConditioningOutput"] | components["schemas"]["FluxControlLoRALoaderOutput"] | components["schemas"]["FluxControlNetOutput"] | components["schemas"]["FluxFillOutput"] | components["schemas"]["FluxKontextOutput"] | components["schemas"]["FluxLoRALoaderOutput"] | components["schemas"]["FluxModelLoaderOutput"] | components["schemas"]["FluxReduxOutput"] | components["schemas"]["ForInvocationOutput"] | components["schemas"]["ForReturnInvocationOutput"] | components["schemas"]["Gemma2EncoderOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["Ideogram4ConditioningOutput"] | components["schemas"]["Ideogram4ModelLoaderOutput"] | components["schemas"]["IfInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ImageGeneratorOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImagePanelCoordinateOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["IntegerGeneratorOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["Krea2ConditioningOutput"] | components["schemas"]["Krea2LoRALoaderOutput"] | components["schemas"]["Krea2ModelLoaderOutput"] | components["schemas"]["Krea2StyleReferenceOutput"] | components["schemas"]["LTX2AudioConditioningOutput"] | components["schemas"]["LTX2DenoiseOutput"] | components["schemas"]["LTX2DurationOutput"] | components["schemas"]["LTX2ExtendConditioningOutput"] | components["schemas"]["LTX2IdealDimensionsOutput"] | components["schemas"]["LTX2ImageConditioningOutput"] | components["schemas"]["LTX2LatentUpsampleOutput"] | components["schemas"]["LTX2LoRACollectionLoaderOutput"] | components["schemas"]["LTX2LoRALoaderOutput"] | components["schemas"]["LTX2ModelLoaderOutput"] | components["schemas"]["LTX2TextEncoderOutput"] | components["schemas"]["LTX2VideoConditioningOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | components["schemas"]["LoopStateOutput"] | components["schemas"]["LoopStateValueOutput"] | components["schemas"]["MDControlListOutput"] | components["schemas"]["MDIPAdapterListOutput"] | components["schemas"]["MDT2IAdapterListOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["MetadataToLorasCollectionOutput"] | components["schemas"]["MetadataToModelOutput"] | components["schemas"]["MetadataToSDXLModelOutput"] | components["schemas"]["MiniMaxH3ConditioningOutput"] | components["schemas"]["MiniMaxH3DenoiseOutput"] | components["schemas"]["MiniMaxH3FrameConditioningOutput"] | components["schemas"]["MiniMaxH3HybridOverlayOutput"] | components["schemas"]["MiniMaxH3LoRACollectionLoaderOutput"] | components["schemas"]["MiniMaxH3LoRALoaderOutput"] | components["schemas"]["MiniMaxH3ModelLoaderOutput"] | components["schemas"]["MiniMaxH3ReferenceConditioningOutput"] | components["schemas"]["MiniMaxH3ReferenceMediaOutput"] | components["schemas"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PiDDecoderOutput"] | components["schemas"]["PromptTemplateOutput"] | components["schemas"]["QwenImage21ConditioningOutput"] | components["schemas"]["QwenImage21ModelLoaderOutput"] | components["schemas"]["QwenImageConditioningOutput"] | components["schemas"]["QwenImageLoRALoaderOutput"] | components["schemas"]["QwenImageModelLoaderOutput"] | components["schemas"]["SD3ConditioningOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["Sd3ModelLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["String2Output"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["StringGeneratorOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["VideoOutput"] | components["schemas"]["WanConditioningOutput"] | components["schemas"]["WanLoRALoaderOutput"] | components["schemas"]["WanModelLoaderOutput"] | components["schemas"]["WanRefImageOutput"] | components["schemas"]["WorkflowReturnGetOutput"] | components["schemas"]["WorkflowReturnOutput"] | components["schemas"]["WorkflowReturnValueOutput"] | components["schemas"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; + [key: string]: components["schemas"]["AnimaConditioningOutput"] | components["schemas"]["AnimaLLLiteOutput"] | components["schemas"]["AnimaLoRALoaderOutput"] | components["schemas"]["AnimaModelLoaderOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["BoundingBoxCollectionOutput"] | components["schemas"]["BoundingBoxOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["CogView4ConditioningOutput"] | components["schemas"]["CogView4ModelLoaderOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["CollectionCartesianInvocationOutput"] | components["schemas"]["CollectionConcatInvocationOutput"] | components["schemas"]["CollectionZipInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ErnieImageConditioningOutput"] | components["schemas"]["ErnieImageModelLoaderOutput"] | components["schemas"]["ExtractVideoRangeOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["Flux2DevLoRALoaderOutput"] | components["schemas"]["Flux2DevModelLoaderOutput"] | components["schemas"]["Flux2KleinLoRALoaderOutput"] | components["schemas"]["Flux2KleinModelLoaderOutput"] | components["schemas"]["FluxConditioningCollectionOutput"] | components["schemas"]["FluxConditioningOutput"] | components["schemas"]["FluxControlLoRALoaderOutput"] | components["schemas"]["FluxControlNetOutput"] | components["schemas"]["FluxFillOutput"] | components["schemas"]["FluxKontextOutput"] | components["schemas"]["FluxLoRALoaderOutput"] | components["schemas"]["FluxModelLoaderOutput"] | components["schemas"]["FluxReduxOutput"] | components["schemas"]["ForInvocationOutput"] | components["schemas"]["ForReturnInvocationOutput"] | components["schemas"]["Gemma2EncoderOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["Ideogram4ConditioningOutput"] | components["schemas"]["Ideogram4ModelLoaderOutput"] | components["schemas"]["IfInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ImageGeneratorOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImagePanelCoordinateOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["IntegerGeneratorOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["Krea2ConditioningOutput"] | components["schemas"]["Krea2LoRALoaderOutput"] | components["schemas"]["Krea2ModelLoaderOutput"] | components["schemas"]["Krea2StyleReferenceOutput"] | components["schemas"]["LTX2AudioConditioningOutput"] | components["schemas"]["LTX2DenoiseOutput"] | components["schemas"]["LTX2DurationOutput"] | components["schemas"]["LTX2ExtendConditioningOutput"] | components["schemas"]["LTX2IdealDimensionsOutput"] | components["schemas"]["LTX2ImageConditioningOutput"] | components["schemas"]["LTX2LatentUpsampleOutput"] | components["schemas"]["LTX2LoRACollectionLoaderOutput"] | components["schemas"]["LTX2LoRALoaderOutput"] | components["schemas"]["LTX2ModelLoaderOutput"] | components["schemas"]["LTX2TextEncoderOutput"] | components["schemas"]["LTX2VideoConditioningOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | components["schemas"]["LoopStateOutput"] | components["schemas"]["LoopStateValueOutput"] | components["schemas"]["MDControlListOutput"] | components["schemas"]["MDIPAdapterListOutput"] | components["schemas"]["MDT2IAdapterListOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["MetadataToLorasCollectionOutput"] | components["schemas"]["MetadataToModelOutput"] | components["schemas"]["MetadataToSDXLModelOutput"] | components["schemas"]["MiniMaxH3ConditioningOutput"] | components["schemas"]["MiniMaxH3DenoiseOutput"] | components["schemas"]["MiniMaxH3FrameConditioningOutput"] | components["schemas"]["MiniMaxH3HybridOverlayOutput"] | components["schemas"]["MiniMaxH3LoRACollectionLoaderOutput"] | components["schemas"]["MiniMaxH3LoRALoaderOutput"] | components["schemas"]["MiniMaxH3ModelLoaderOutput"] | components["schemas"]["MiniMaxH3ReferenceConditioningOutput"] | components["schemas"]["MiniMaxH3ReferenceMediaOutput"] | components["schemas"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PiDDecoderOutput"] | components["schemas"]["PromptTemplateOutput"] | components["schemas"]["QwenImage21ConditioningOutput"] | components["schemas"]["QwenImage21ModelLoaderOutput"] | components["schemas"]["QwenImageConditioningOutput"] | components["schemas"]["QwenImageControlOutput"] | components["schemas"]["QwenImageLoRALoaderOutput"] | components["schemas"]["QwenImageModelLoaderOutput"] | components["schemas"]["SD3ConditioningOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["Sd3ModelLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["String2Output"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["StringGeneratorOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["VideoOutput"] | components["schemas"]["WanConditioningOutput"] | components["schemas"]["WanLoRALoaderOutput"] | components["schemas"]["WanModelLoaderOutput"] | components["schemas"]["WanRefImageOutput"] | components["schemas"]["WorkflowReturnGetOutput"] | components["schemas"]["WorkflowReturnOutput"] | components["schemas"]["WorkflowReturnValueOutput"] | components["schemas"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; }; /** * Errors @@ -22178,7 +22267,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageControlInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -22206,7 +22295,7 @@ export type components = { * Result * @description The result of the invocation */ - result: components["schemas"]["AnimaConditioningOutput"] | components["schemas"]["AnimaLLLiteOutput"] | components["schemas"]["AnimaLoRALoaderOutput"] | components["schemas"]["AnimaModelLoaderOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["BoundingBoxCollectionOutput"] | components["schemas"]["BoundingBoxOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["CogView4ConditioningOutput"] | components["schemas"]["CogView4ModelLoaderOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["CollectionCartesianInvocationOutput"] | components["schemas"]["CollectionConcatInvocationOutput"] | components["schemas"]["CollectionZipInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ErnieImageConditioningOutput"] | components["schemas"]["ErnieImageModelLoaderOutput"] | components["schemas"]["ExtractVideoRangeOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["Flux2DevLoRALoaderOutput"] | components["schemas"]["Flux2DevModelLoaderOutput"] | components["schemas"]["Flux2KleinLoRALoaderOutput"] | components["schemas"]["Flux2KleinModelLoaderOutput"] | components["schemas"]["FluxConditioningCollectionOutput"] | components["schemas"]["FluxConditioningOutput"] | components["schemas"]["FluxControlLoRALoaderOutput"] | components["schemas"]["FluxControlNetOutput"] | components["schemas"]["FluxFillOutput"] | components["schemas"]["FluxKontextOutput"] | components["schemas"]["FluxLoRALoaderOutput"] | components["schemas"]["FluxModelLoaderOutput"] | components["schemas"]["FluxReduxOutput"] | components["schemas"]["ForInvocationOutput"] | components["schemas"]["ForReturnInvocationOutput"] | components["schemas"]["Gemma2EncoderOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["Ideogram4ConditioningOutput"] | components["schemas"]["Ideogram4ModelLoaderOutput"] | components["schemas"]["IfInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ImageGeneratorOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImagePanelCoordinateOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["IntegerGeneratorOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["Krea2ConditioningOutput"] | components["schemas"]["Krea2LoRALoaderOutput"] | components["schemas"]["Krea2ModelLoaderOutput"] | components["schemas"]["Krea2StyleReferenceOutput"] | components["schemas"]["LTX2AudioConditioningOutput"] | components["schemas"]["LTX2DenoiseOutput"] | components["schemas"]["LTX2DurationOutput"] | components["schemas"]["LTX2ExtendConditioningOutput"] | components["schemas"]["LTX2IdealDimensionsOutput"] | components["schemas"]["LTX2ImageConditioningOutput"] | components["schemas"]["LTX2LatentUpsampleOutput"] | components["schemas"]["LTX2LoRACollectionLoaderOutput"] | components["schemas"]["LTX2LoRALoaderOutput"] | components["schemas"]["LTX2ModelLoaderOutput"] | components["schemas"]["LTX2TextEncoderOutput"] | components["schemas"]["LTX2VideoConditioningOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | components["schemas"]["LoopStateOutput"] | components["schemas"]["LoopStateValueOutput"] | components["schemas"]["MDControlListOutput"] | components["schemas"]["MDIPAdapterListOutput"] | components["schemas"]["MDT2IAdapterListOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["MetadataToLorasCollectionOutput"] | components["schemas"]["MetadataToModelOutput"] | components["schemas"]["MetadataToSDXLModelOutput"] | components["schemas"]["MiniMaxH3ConditioningOutput"] | components["schemas"]["MiniMaxH3DenoiseOutput"] | components["schemas"]["MiniMaxH3FrameConditioningOutput"] | components["schemas"]["MiniMaxH3HybridOverlayOutput"] | components["schemas"]["MiniMaxH3LoRACollectionLoaderOutput"] | components["schemas"]["MiniMaxH3LoRALoaderOutput"] | components["schemas"]["MiniMaxH3ModelLoaderOutput"] | components["schemas"]["MiniMaxH3ReferenceConditioningOutput"] | components["schemas"]["MiniMaxH3ReferenceMediaOutput"] | components["schemas"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PiDDecoderOutput"] | components["schemas"]["PromptTemplateOutput"] | components["schemas"]["QwenImage21ConditioningOutput"] | components["schemas"]["QwenImage21ModelLoaderOutput"] | components["schemas"]["QwenImageConditioningOutput"] | components["schemas"]["QwenImageLoRALoaderOutput"] | components["schemas"]["QwenImageModelLoaderOutput"] | components["schemas"]["SD3ConditioningOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["Sd3ModelLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["String2Output"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["StringGeneratorOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["VideoOutput"] | components["schemas"]["WanConditioningOutput"] | components["schemas"]["WanLoRALoaderOutput"] | components["schemas"]["WanModelLoaderOutput"] | components["schemas"]["WanRefImageOutput"] | components["schemas"]["WorkflowReturnGetOutput"] | components["schemas"]["WorkflowReturnOutput"] | components["schemas"]["WorkflowReturnValueOutput"] | components["schemas"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; + result: components["schemas"]["AnimaConditioningOutput"] | components["schemas"]["AnimaLLLiteOutput"] | components["schemas"]["AnimaLoRALoaderOutput"] | components["schemas"]["AnimaModelLoaderOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["BoundingBoxCollectionOutput"] | components["schemas"]["BoundingBoxOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["CLIPSkipInvocationOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["CogView4ConditioningOutput"] | components["schemas"]["CogView4ModelLoaderOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["CollectionCartesianInvocationOutput"] | components["schemas"]["CollectionConcatInvocationOutput"] | components["schemas"]["CollectionZipInvocationOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ErnieImageConditioningOutput"] | components["schemas"]["ErnieImageModelLoaderOutput"] | components["schemas"]["ExtractVideoRangeOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FloatGeneratorOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["Flux2DevLoRALoaderOutput"] | components["schemas"]["Flux2DevModelLoaderOutput"] | components["schemas"]["Flux2KleinLoRALoaderOutput"] | components["schemas"]["Flux2KleinModelLoaderOutput"] | components["schemas"]["FluxConditioningCollectionOutput"] | components["schemas"]["FluxConditioningOutput"] | components["schemas"]["FluxControlLoRALoaderOutput"] | components["schemas"]["FluxControlNetOutput"] | components["schemas"]["FluxFillOutput"] | components["schemas"]["FluxKontextOutput"] | components["schemas"]["FluxLoRALoaderOutput"] | components["schemas"]["FluxModelLoaderOutput"] | components["schemas"]["FluxReduxOutput"] | components["schemas"]["ForInvocationOutput"] | components["schemas"]["ForReturnInvocationOutput"] | components["schemas"]["Gemma2EncoderOutput"] | components["schemas"]["GradientMaskOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["Ideogram4ConditioningOutput"] | components["schemas"]["Ideogram4ModelLoaderOutput"] | components["schemas"]["IfInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ImageGeneratorOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImagePanelCoordinateOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["IntegerGeneratorOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["Krea2ConditioningOutput"] | components["schemas"]["Krea2LoRALoaderOutput"] | components["schemas"]["Krea2ModelLoaderOutput"] | components["schemas"]["Krea2StyleReferenceOutput"] | components["schemas"]["LTX2AudioConditioningOutput"] | components["schemas"]["LTX2DenoiseOutput"] | components["schemas"]["LTX2DurationOutput"] | components["schemas"]["LTX2ExtendConditioningOutput"] | components["schemas"]["LTX2IdealDimensionsOutput"] | components["schemas"]["LTX2ImageConditioningOutput"] | components["schemas"]["LTX2LatentUpsampleOutput"] | components["schemas"]["LTX2LoRACollectionLoaderOutput"] | components["schemas"]["LTX2LoRALoaderOutput"] | components["schemas"]["LTX2ModelLoaderOutput"] | components["schemas"]["LTX2TextEncoderOutput"] | components["schemas"]["LTX2VideoConditioningOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["LatentsMetaOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LoRALoaderOutput"] | components["schemas"]["LoRASelectorOutput"] | components["schemas"]["LoopStateOutput"] | components["schemas"]["LoopStateValueOutput"] | components["schemas"]["MDControlListOutput"] | components["schemas"]["MDIPAdapterListOutput"] | components["schemas"]["MDT2IAdapterListOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["MetadataToLorasCollectionOutput"] | components["schemas"]["MetadataToModelOutput"] | components["schemas"]["MetadataToSDXLModelOutput"] | components["schemas"]["MiniMaxH3ConditioningOutput"] | components["schemas"]["MiniMaxH3DenoiseOutput"] | components["schemas"]["MiniMaxH3FrameConditioningOutput"] | components["schemas"]["MiniMaxH3HybridOverlayOutput"] | components["schemas"]["MiniMaxH3LoRACollectionLoaderOutput"] | components["schemas"]["MiniMaxH3LoRALoaderOutput"] | components["schemas"]["MiniMaxH3ModelLoaderOutput"] | components["schemas"]["MiniMaxH3ReferenceConditioningOutput"] | components["schemas"]["MiniMaxH3ReferenceMediaOutput"] | components["schemas"]["ModelIdentifierOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PBRMapsOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["PiDDecoderOutput"] | components["schemas"]["PromptTemplateOutput"] | components["schemas"]["QwenImage21ConditioningOutput"] | components["schemas"]["QwenImage21ModelLoaderOutput"] | components["schemas"]["QwenImageConditioningOutput"] | components["schemas"]["QwenImageControlOutput"] | components["schemas"]["QwenImageLoRALoaderOutput"] | components["schemas"]["QwenImageModelLoaderOutput"] | components["schemas"]["SD3ConditioningOutput"] | components["schemas"]["SDXLLoRALoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["Sd3ModelLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["String2Output"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["StringGeneratorOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["VideoOutput"] | components["schemas"]["WanConditioningOutput"] | components["schemas"]["WanLoRALoaderOutput"] | components["schemas"]["WanModelLoaderOutput"] | components["schemas"]["WanRefImageOutput"] | components["schemas"]["WorkflowReturnGetOutput"] | components["schemas"]["WorkflowReturnOutput"] | components["schemas"]["WorkflowReturnValueOutput"] | components["schemas"]["ZImageConditioningOutput"] | components["schemas"]["ZImageControlOutput"] | components["schemas"]["ZImageLoRALoaderOutput"] | components["schemas"]["ZImageModelLoaderOutput"]; }; /** * InvocationErrorEvent @@ -22260,7 +22349,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageControlInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -22562,6 +22651,7 @@ export type components = { qwen_image_2_1_l2i: components["schemas"]["ImageOutput"]; qwen_image_2_1_model_loader: components["schemas"]["QwenImage21ModelLoaderOutput"]; qwen_image_2_1_text_encoder: components["schemas"]["QwenImage21ConditioningOutput"]; + qwen_image_control: components["schemas"]["QwenImageControlOutput"]; qwen_image_denoise: components["schemas"]["LatentsOutput"]; qwen_image_i2l: components["schemas"]["LatentsOutput"]; qwen_image_l2i: components["schemas"]["ImageOutput"]; @@ -22705,7 +22795,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageControlInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -22810,7 +22900,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["AtlasCloudImageGenerationInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanLogicInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CollectionCartesianInvocation"] | components["schemas"]["CollectionConcatInvocation"] | components["schemas"]["CollectionZipInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["ForInvocation"] | components["schemas"]["ForReturnInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2StyleReferenceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LTX2AudioConditioningInvocation"] | components["schemas"]["LTX2DenoiseInvocation"] | components["schemas"]["LTX2DurationInvocation"] | components["schemas"]["LTX2ExtendConditioningInvocation"] | components["schemas"]["LTX2IdealDimensionsInvocation"] | components["schemas"]["LTX2ImageConditioningInvocation"] | components["schemas"]["LTX2LatentUpsampleInvocation"] | components["schemas"]["LTX2LatentsToVideoInvocation"] | components["schemas"]["LTX2LoRACollectionLoader"] | components["schemas"]["LTX2LoRALoaderInvocation"] | components["schemas"]["LTX2ModelLoaderInvocation"] | components["schemas"]["LTX2TextEncoderInvocation"] | components["schemas"]["LTX2VideoConditioningInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["MiniMaxH3DenoiseInvocation"] | components["schemas"]["MiniMaxH3FrameConditioningInvocation"] | components["schemas"]["MiniMaxH3HybridOverlayInvocation"] | components["schemas"]["MiniMaxH3IdealDimensionsInvocation"] | components["schemas"]["MiniMaxH3ImageReferenceInvocation"] | components["schemas"]["MiniMaxH3LatentsToImageInvocation"] | components["schemas"]["MiniMaxH3LatentsToVideoInvocation"] | components["schemas"]["MiniMaxH3LoRACollectionLoader"] | components["schemas"]["MiniMaxH3LoRALoaderInvocation"] | components["schemas"]["MiniMaxH3ModelLoaderInvocation"] | components["schemas"]["MiniMaxH3ReferenceConditioningInvocation"] | components["schemas"]["MiniMaxH3TextEncoderInvocation"] | components["schemas"]["MiniMaxH3VideoReferenceInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImage21DenoiseInvocation"] | components["schemas"]["QwenImage21ImageToLatentsInvocation"] | components["schemas"]["QwenImage21LatentsToImageInvocation"] | components["schemas"]["QwenImage21ModelLoaderInvocation"] | components["schemas"]["QwenImage21TextEncoderInvocation"] | components["schemas"]["QwenImageControlInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StateEmptyInvocation"] | components["schemas"]["StateGetInvocation"] | components["schemas"]["StateMergeInvocation"] | components["schemas"]["StateSetInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -37271,7 +37361,7 @@ export type components = { * Config * @description The installed model's config */ - config: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + config: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; /** * ModelInstallDownloadProgressEvent @@ -37437,7 +37527,7 @@ export type components = { * Config Out * @description After successful installation, this will hold the configuration object. */ - config_out?: (components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]) | null; + config_out?: (components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]) | null; /** * Inplace * @description Leave model in its current location; otherwise install under models directory @@ -37523,7 +37613,7 @@ export type components = { * Config * @description The model's config */ - config: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + config: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; /** * @description The submodel type, if any * @default null @@ -37550,7 +37640,7 @@ export type components = { * Config * @description The model's config */ - config: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + config: components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; /** * @description The submodel type, if any * @default null @@ -37777,7 +37867,7 @@ export type components = { */ ModelsList: { /** Models */ - models: (components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"])[]; + models: (components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"])[]; }; /** * Multiply Integers @@ -41338,6 +41428,159 @@ export type components = { */ type: "qwen_image_conditioning_output"; }; + /** + * QwenImageControlField + * @description Qwen Image Fun-ControlNet conditioning: a control image, an inpaint image with its mask, or both. + */ + QwenImageControlField: { + /** + * Image Name + * @description The preprocessed control image (Canny, depth, pose, ...) + * @default null + */ + image_name?: string | null; + /** + * Inpaint Image Name + * @description The image to inpaint + * @default null + */ + inpaint_image_name?: string | null; + /** + * Inpaint Mask Name + * @description The inpaint mask; white is regenerated + * @default null + */ + inpaint_mask_name?: string | null; + /** @description The Qwen Image ControlNet model */ + control_model: components["schemas"]["ModelIdentifierField"]; + /** + * Control Context Scale + * @description Strength of the control signal. Recommended range: 0.70-0.95. + * @default 0.85 + */ + control_context_scale?: number; + /** + * Begin Step Percent + * @description When the control is first applied (% of total steps) + * @default 0 + */ + begin_step_percent?: number; + /** + * End Step Percent + * @description When the control is last applied (% of total steps) + * @default 1 + */ + end_step_percent?: number; + /** + * Tiled + * @description Encode the control images in tiles. The denoise encodes them at generation size, which for an upscale is the enlarged frame -- too large for an untiled encode on consumer hardware. + * @default false + */ + tiled?: boolean; + /** + * Tile Size + * @description The tile size for VAE tiling in pixels (image space). If set to 0, the default tile size for the model will be used. Larger tile sizes generally produce better results at the cost of higher memory usage. Values between 1 and 64 are raised to 64. + * @default 0 + */ + tile_size?: number; + }; + /** + * Qwen Image ControlNet + * @description Configure the Qwen Image Fun-ControlNet-Union for spatial control, inpainting, or both. + * + * Takes a preprocessed control image (Canny, HED, depth, pose, MLSD, ...) and/or an image to inpaint with its mask + * (white is regenerated), plus the Qwen Image ControlNet model. Recommended control scale: 0.70-0.95. + */ + QwenImageControlInvocation: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** + * @description The preprocessed control image (Canny, HED, depth, pose, MLSD, ...) + * @default null + */ + image?: components["schemas"]["ImageField"] | null; + /** + * @description The image to inpaint. Goes together with the inpaint mask. + * @default null + */ + inpaint_image?: components["schemas"]["ImageField"] | null; + /** + * @description The inpaint mask: white is regenerated, black is kept. Goes together with the inpaint image. + * @default null + */ + inpaint_mask?: components["schemas"]["ImageField"] | null; + /** + * Control Model + * @description ControlNet model to load + * @default null + */ + control_model?: components["schemas"]["ModelIdentifierField"] | null; + /** + * Control Scale + * @description Strength of the control signal. Recommended range: 0.70-0.95. + * @default 0.85 + */ + control_context_scale?: number; + /** + * Begin Step Percent + * @description When the control is first applied (% of total steps) + * @default 0 + */ + begin_step_percent?: number; + /** + * End Step Percent + * @description When the control is last applied (% of total steps) + * @default 1 + */ + end_step_percent?: number; + /** + * Tiled + * @description Processing using overlapping tiles (reduce memory consumption) + * @default false + */ + tiled?: boolean; + /** + * Tile Size + * @description The tile size for VAE tiling in pixels (image space). If set to 0, the default tile size for the model will be used. Larger tile sizes generally produce better results at the cost of higher memory usage. Values between 1 and 64 are raised to 64. + * @default 0 + */ + tile_size?: number; + /** + * type + * @default qwen_image_control + * @constant + */ + type: "qwen_image_control"; + }; + /** + * QwenImageControlOutput + * @description Qwen Image Control output containing control configuration. + */ + QwenImageControlOutput: { + /** @description Qwen Image control conditioning */ + control: components["schemas"]["QwenImageControlField"]; + /** + * type + * @default qwen_image_control_output + * @constant + */ + type: "qwen_image_control_output"; + }; /** * Denoise - Qwen Image * @description Run the denoising process with a Qwen Image model. @@ -41449,6 +41692,16 @@ export type components = { * @default null */ shift?: number | null; + /** + * @description Qwen Image ControlNet conditioning: spatial control (Canny, depth, pose, ...) and/or inpainting. + * @default null + */ + control?: components["schemas"]["QwenImageControlField"] | null; + /** + * @description VAE Required for control conditioning. + * @default null + */ + vae?: components["schemas"]["VAEField"] | null; /** * type * @default qwen_image_denoise @@ -54329,7 +54582,7 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Validation Error */ @@ -54361,7 +54614,7 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Validation Error */ @@ -54413,7 +54666,7 @@ export interface operations { * "upcast_attention": false * } */ - "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -54527,7 +54780,7 @@ export interface operations { * "upcast_attention": false * } */ - "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -54600,7 +54853,7 @@ export interface operations { * "upcast_attention": false * } */ - "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ @@ -55401,7 +55654,7 @@ export interface operations { * "upcast_attention": false * } */ - "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; + "application/json": components["schemas"]["Main_Diffusers_SD1_Config"] | components["schemas"]["Main_Diffusers_SD2_Config"] | components["schemas"]["Main_Diffusers_SDXL_Config"] | components["schemas"]["Main_Diffusers_SDXLRefiner_Config"] | components["schemas"]["Main_Diffusers_SD3_Config"] | components["schemas"]["Main_Diffusers_FLUX_Config"] | components["schemas"]["Main_Diffusers_Flux2_Config"] | components["schemas"]["Main_Diffusers_CogView4_Config"] | components["schemas"]["Main_Diffusers_QwenImage_Config"] | components["schemas"]["Main_Diffusers_QwenImage21_Config"] | components["schemas"]["Main_Diffusers_Wan_Config"] | components["schemas"]["Main_Diffusers_ZImage_Config"] | components["schemas"]["Main_Diffusers_ErnieImage_Config"] | components["schemas"]["Main_Diffusers_Ideogram4_Config"] | components["schemas"]["Main_Diffusers_Krea2_Config"] | components["schemas"]["Main_Diffusers_MiniMaxH3_Config"] | components["schemas"]["Main_Diffusers_LTX2_Config"] | components["schemas"]["Main_Checkpoint_SD1_Config"] | components["schemas"]["Main_Checkpoint_SD2_Config"] | components["schemas"]["Main_Checkpoint_SDXL_Config"] | components["schemas"]["Main_Checkpoint_SDXLRefiner_Config"] | components["schemas"]["Main_Checkpoint_Flux2_Config"] | components["schemas"]["Main_Checkpoint_FLUX_Config"] | components["schemas"]["Main_Checkpoint_QwenImage_Config"] | components["schemas"]["Main_Checkpoint_QwenImage21_Config"] | components["schemas"]["Main_Checkpoint_Wan_Config"] | components["schemas"]["Main_Checkpoint_ZImage_Config"] | components["schemas"]["Main_Checkpoint_ErnieImage_Config"] | components["schemas"]["Main_Checkpoint_Ideogram4_Config"] | components["schemas"]["Main_Checkpoint_Krea2_Config"] | components["schemas"]["Main_Checkpoint_Anima_Config"] | components["schemas"]["Main_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Main_Checkpoint_LTX2_Config"] | components["schemas"]["Main_BnBNF4_FLUX_Config"] | components["schemas"]["Main_GGUF_Flux2_Config"] | components["schemas"]["Main_GGUF_FLUX_Config"] | components["schemas"]["Main_GGUF_QwenImage_Config"] | components["schemas"]["Main_GGUF_QwenImage21_Config"] | components["schemas"]["Main_GGUF_Wan_Config"] | components["schemas"]["Main_GGUF_ZImage_Config"] | components["schemas"]["Main_GGUF_Krea2_Config"] | components["schemas"]["Main_GGUF_Ideogram4_Config"] | components["schemas"]["Main_GGUF_ErnieImage_Config"] | components["schemas"]["Main_SDNQ_Diffusers_Flux2_Config"] | components["schemas"]["Main_SDNQ_Diffusers_FLUX_Config"] | components["schemas"]["Main_SDNQ_Diffusers_ZImage_Config"] | components["schemas"]["VAE_Checkpoint_SD1_Config"] | components["schemas"]["VAE_Checkpoint_SD2_Config"] | components["schemas"]["VAE_Checkpoint_SDXL_Config"] | components["schemas"]["VAE_Checkpoint_FLUX_Config"] | components["schemas"]["VAE_Checkpoint_SD3_Config"] | components["schemas"]["VAE_Checkpoint_Flux2_Config"] | components["schemas"]["VAE_Checkpoint_Wan_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage_Config"] | components["schemas"]["VAE_Checkpoint_Anima_Config"] | components["schemas"]["VAE_Checkpoint_QwenImage21_Config"] | components["schemas"]["VAE_Diffusers_SD1_Config"] | components["schemas"]["VAE_Diffusers_SDXL_Config"] | components["schemas"]["VAE_Diffusers_FLUX_Config"] | components["schemas"]["VAE_Diffusers_SD3_Config"] | components["schemas"]["VAE_Diffusers_Flux2_Config"] | components["schemas"]["VAE_Diffusers_Wan_Config"] | components["schemas"]["VAE_Diffusers_QwenImage21_Config"] | components["schemas"]["PiDDecoder_Checkpoint_FLUX_Config"] | components["schemas"]["PiDDecoder_Checkpoint_Flux2_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SD3_Config"] | components["schemas"]["PiDDecoder_Checkpoint_SDXL_Config"] | components["schemas"]["PiDDecoder_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Checkpoint_SD1_Config"] | components["schemas"]["ControlNet_Checkpoint_SD2_Config"] | components["schemas"]["ControlNet_Checkpoint_SDXL_Config"] | components["schemas"]["ControlNet_Checkpoint_FLUX_Config"] | components["schemas"]["ControlNet_Checkpoint_ZImage_Config"] | components["schemas"]["ControlNet_Checkpoint_Anima_Config"] | components["schemas"]["ControlNet_Checkpoint_QwenImage_Config"] | components["schemas"]["ControlNet_Diffusers_SD1_Config"] | components["schemas"]["ControlNet_Diffusers_SD2_Config"] | components["schemas"]["ControlNet_Diffusers_SDXL_Config"] | components["schemas"]["ControlNet_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_SD1_Config"] | components["schemas"]["LoRA_LyCORIS_SD2_Config"] | components["schemas"]["LoRA_LyCORIS_SDXL_Config"] | components["schemas"]["LoRA_LyCORIS_Flux2_Config"] | components["schemas"]["LoRA_LyCORIS_FLUX_Config"] | components["schemas"]["LoRA_LyCORIS_ZImage_Config"] | components["schemas"]["LoRA_LyCORIS_Krea2_Config"] | components["schemas"]["LoRA_LyCORIS_QwenImage_Config"] | components["schemas"]["LoRA_LyCORIS_LTX2_Config"] | components["schemas"]["LoRA_LyCORIS_MiniMaxH3_Config"] | components["schemas"]["LoRA_LyCORIS_Wan_Config"] | components["schemas"]["LoRA_LyCORIS_Anima_Config"] | components["schemas"]["LoRA_OMI_SDXL_Config"] | components["schemas"]["LoRA_OMI_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_SD1_Config"] | components["schemas"]["LoRA_Diffusers_SD2_Config"] | components["schemas"]["LoRA_Diffusers_SDXL_Config"] | components["schemas"]["LoRA_Diffusers_Flux2_Config"] | components["schemas"]["LoRA_Diffusers_FLUX_Config"] | components["schemas"]["LoRA_Diffusers_ZImage_Config"] | components["schemas"]["ControlLoRA_LyCORIS_FLUX_Config"] | components["schemas"]["T5Encoder_T5Encoder_Config"] | components["schemas"]["T5Encoder_BnBLLMint8_Config"] | components["schemas"]["T5Encoder_SDNQ_Config"] | components["schemas"]["T5Encoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_MiniMaxH3_Config"] | components["schemas"]["Qwen3VLEncoder_Checkpoint_Config"] | components["schemas"]["Qwen3VLEncoder_GGUF_Config"] | components["schemas"]["Qwen3VLEncoder_Qwen3VLEncoder_Config"] | components["schemas"]["Qwen35Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_Qwen3Encoder_Config"] | components["schemas"]["Qwen3Encoder_Checkpoint_Config"] | components["schemas"]["Qwen3Encoder_GGUF_Config"] | components["schemas"]["Qwen3Encoder_SDNQ_Folder_Config"] | components["schemas"]["MistralEncoder_Diffusers_Config"] | components["schemas"]["MistralEncoder_Checkpoint_Config"] | components["schemas"]["MistralEncoder_GGUF_Config"] | components["schemas"]["Gemma2Encoder_Gemma2Encoder_Config"] | components["schemas"]["Gemma4Encoder_Gemma4Encoder_LTX2_Config"] | components["schemas"]["Gemma2Encoder_GGUF_Config"] | components["schemas"]["QwenVLEncoder_Diffusers_Config"] | components["schemas"]["QwenVLEncoder_Checkpoint_Config"] | components["schemas"]["WanT5Encoder_WanT5Encoder_Config"] | components["schemas"]["TI_File_SD1_Config"] | components["schemas"]["TI_File_SD2_Config"] | components["schemas"]["TI_File_SDXL_Config"] | components["schemas"]["TI_Folder_SD1_Config"] | components["schemas"]["TI_Folder_SD2_Config"] | components["schemas"]["TI_Folder_SDXL_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD1_Config"] | components["schemas"]["IPAdapter_InvokeAI_SD2_Config"] | components["schemas"]["IPAdapter_InvokeAI_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD1_Config"] | components["schemas"]["IPAdapter_Checkpoint_SD2_Config"] | components["schemas"]["IPAdapter_Checkpoint_SDXL_Config"] | components["schemas"]["IPAdapter_Checkpoint_FLUX_Config"] | components["schemas"]["T2IAdapter_Diffusers_SD1_Config"] | components["schemas"]["T2IAdapter_Diffusers_SDXL_Config"] | components["schemas"]["Spandrel_Checkpoint_Config"] | components["schemas"]["CLIPEmbed_Diffusers_G_Config"] | components["schemas"]["CLIPEmbed_Diffusers_L_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_G_Config"] | components["schemas"]["CLIPEmbed_Checkpoint_L_Config"] | components["schemas"]["CLIPVision_Diffusers_Config"] | components["schemas"]["SigLIP_Diffusers_Config"] | components["schemas"]["FLUXRedux_Checkpoint_Config"] | components["schemas"]["LTX2DurationHead_Checkpoint_Config"] | components["schemas"]["LlavaOnevision_Diffusers_Config"] | components["schemas"]["TextLLM_Diffusers_Config"] | components["schemas"]["ExternalApiModelConfig"] | components["schemas"]["Unknown_Config"]; }; }; /** @description Bad request */ diff --git a/invokeai/frontend/webv2/public/locales/en.json b/invokeai/frontend/webv2/public/locales/en.json index 5ed4de02fc2..553dc2c6815 100644 --- a/invokeai/frontend/webv2/public/locales/en.json +++ b/invokeai/frontend/webv2/public/locales/en.json @@ -3747,6 +3747,7 @@ "content_shuffle": "Content shuffle", "depth_anything_depth_estimation": "Depth Anything", "dw_openpose_detection": "DW Openpose", + "grayscale": "Grayscale", "hed_edge_detection": "HED", "img_blur": "Blur", "img_noise": "Noise", @@ -3769,6 +3770,7 @@ "anima_lllite": "Anima ControlNet-LLLite", "control_lora": "Control LoRA", "controlnet": "ControlNet", + "qwen_image_control": "Qwen Image ControlNet", "t2i_adapter": "T2I Adapter", "z_image_control": "Z-Image ControlNet" }, @@ -3797,6 +3799,8 @@ "lllite_channels_unknown": "This ControlNet-LLLite model's adapter type is unknown. Re-identify it in the Model Manager.", "lllite_inpaint_adapter": "This is an inpainting ControlNet-LLLite adapter; a control layer needs a control adapter.", "missing_model": "Select a control model before generating.", + "qwen_image_control_limit": "Only one Qwen Image ControlNet can be used at a time.", + "qwen_image_edit_control": "Qwen Image ControlNet is not compatible with Qwen Image Edit models.", "switch_adapter_kind": "Switch the adapter type to {{kind}} to use this layer with the selected model.", "unsupported_adapter": "This control adapter is not supported by the selected base model.", "z_image_control_limit": "Only one Z-Image control can be used at a time." diff --git a/invokeai/frontend/webv2/src/features/generation/core/__fixtures__/architectureCapabilities.json b/invokeai/frontend/webv2/src/features/generation/core/__fixtures__/architectureCapabilities.json index 005e93e4968..89bbf689e3c 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/__fixtures__/architectureCapabilities.json +++ b/invokeai/frontend/webv2/src/features/generation/core/__fixtures__/architectureCapabilities.json @@ -789,7 +789,9 @@ "guidance_max": null, "scheduler_set": "standard", "scheduler_applies_to_graph": false, - "control_kinds": [], + "control_kinds": [ + "qwen_image_control" + ], "max_reference_images": 5, "reference_images_require_variant": "edit", "supports_regional_guidance": false, diff --git a/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/generateGraphNodeTypes.json b/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/generateGraphNodeTypes.json index 61bcecb9982..e1a76961741 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/generateGraphNodeTypes.json +++ b/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/generateGraphNodeTypes.json @@ -1523,7 +1523,8 @@ "negative_conditioning", "positive_conditioning", "seed", - "transformer" + "transformer", + "vae" ], "literalInputs": { "cfg_scale": [ diff --git a/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json b/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json new file mode 100644 index 00000000000..19fd1898747 --- /dev/null +++ b/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json @@ -0,0 +1,1160 @@ +{ + "_comment": "Generated by compileCanvasGraph.test.ts; regenerate with `vitest -u`. Consumed by tests/app/invocations/test_frontend_qwen_image_control_graphs.py, which validates the graphs against the backend invocations.", + "inpaint_control_layer": { + "edges": [ + { + "destination": { + "field": "vae", + "node_id": "canvas_l2i" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "latents", + "node_id": "canvas_l2i" + }, + "source": { + "field": "latents", + "node_id": "denoise_latents" + } + }, + { + "destination": { + "field": "transformer", + "node_id": "denoise_latents" + }, + "source": { + "field": "transformer", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "vae", + "node_id": "denoise_latents" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "pos_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "pos_cond" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "positive_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "pos_cond" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "neg_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "neg_cond" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "negative_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "neg_cond" + } + }, + { + "destination": { + "field": "seed", + "node_id": "denoise_latents" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "seed", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "positive_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "negative_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "metadata", + "node_id": "canvas_output" + }, + "source": { + "field": "metadata", + "node_id": "core_metadata_0_i" + } + }, + { + "destination": { + "field": "vae", + "node_id": "canvas_i2l" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "latents", + "node_id": "denoise_latents" + }, + "source": { + "field": "latents", + "node_id": "canvas_i2l" + } + }, + { + "destination": { + "field": "vae", + "node_id": "create_gradient_mask" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "denoise_mask", + "node_id": "denoise_latents" + }, + "source": { + "field": "denoise_mask", + "node_id": "create_gradient_mask" + } + }, + { + "destination": { + "field": "mask", + "node_id": "expand_mask" + }, + "source": { + "field": "expanded_mask_area", + "node_id": "create_gradient_mask" + } + }, + { + "destination": { + "field": "layer_upper", + "node_id": "canvas_output" + }, + "source": { + "field": "image", + "node_id": "canvas_l2i" + } + }, + { + "destination": { + "field": "mask", + "node_id": "canvas_output" + }, + "source": { + "field": "image", + "node_id": "expand_mask" + } + }, + { + "destination": { + "field": "inpaint_mask", + "node_id": "qwen_image_control_q-control" + }, + "source": { + "field": "image", + "node_id": "qwen_image_control_mask_q-control" + } + }, + { + "destination": { + "field": "control", + "node_id": "denoise_latents" + }, + "source": { + "field": "control", + "node_id": "qwen_image_control_q-control" + } + } + ], + "id": "qwen_image_control_canvas_inpaint", + "nodes": { + "negative_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "negative_prompt", + "type": "string" + }, + "positive_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "positive_prompt", + "type": "string" + }, + "seed": { + "is_intermediate": true, + "use_cache": true, + "id": "seed", + "type": "integer" + }, + "model_loader": { + "is_intermediate": true, + "use_cache": true, + "id": "model_loader", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "type": "qwen_image_model_loader" + }, + "pos_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "pos_cond", + "type": "qwen_image_text_encoder" + }, + "neg_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "neg_cond", + "type": "qwen_image_text_encoder" + }, + "denoise_latents": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "height": 1024, + "id": "denoise_latents", + "steps": 40, + "type": "qwen_image_denoise", + "width": 768, + "denoising_start": 0.4, + "denoising_end": 1 + }, + "core_metadata_0_i": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "cfg_rescale_multiplier": 0, + "generation_mode": "qwen_image_inpaint", + "height": 1024, + "id": "core_metadata_0_i", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "rand_device": "cpu", + "seamless_x": false, + "seamless_y": false, + "steps": 40, + "type": "core_metadata", + "width": 768, + "qwen_image_quantization": "none", + "qwen_image_shift": "auto", + "clip_skip": 0, + "strength": 0.6 + }, + "canvas_i2l": { + "is_intermediate": true, + "use_cache": true, + "id": "canvas_i2l", + "type": "qwen_image_i2l", + "image": { + "image_name": "canvas-composite.png" + } + }, + "create_gradient_mask": { + "is_intermediate": true, + "use_cache": true, + "coherence_mode": "Gaussian Blur", + "edge_radius": 16, + "fp32": false, + "id": "create_gradient_mask", + "image": { + "image_name": "canvas-composite.png" + }, + "minimum_denoise": 0, + "type": "create_gradient_mask", + "mask": { + "image_name": "canvas-mask.png" + } + }, + "expand_mask": { + "is_intermediate": true, + "use_cache": true, + "fade_size_px": 16, + "id": "expand_mask", + "type": "expand_mask_with_fade" + }, + "canvas_l2i": { + "is_intermediate": true, + "use_cache": false, + "id": "canvas_l2i", + "type": "qwen_image_l2i" + }, + "canvas_output": { + "is_intermediate": true, + "use_cache": false, + "layer_base": { + "image_name": "canvas-composite.png" + }, + "type": "invokeai_img_blend", + "id": "canvas_output" + }, + "qwen_image_control_q-control": { + "is_intermediate": true, + "use_cache": true, + "begin_step_percent": 0, + "control_context_scale": 0.85, + "control_model": { + "base": "qwen-image", + "key": "qwen-union", + "name": "Qwen Image ControlNet Union", + "type": "controlnet", + "hash": "blake3:union" + }, + "end_step_percent": 1, + "id": "qwen_image_control_q-control", + "image": { + "image_name": "q-control.png" + }, + "type": "qwen_image_control", + "inpaint_image": { + "image_name": "canvas-composite.png" + } + }, + "qwen_image_control_mask_q-control": { + "is_intermediate": true, + "use_cache": true, + "id": "qwen_image_control_mask_q-control", + "max": 0, + "min": 255, + "type": "img_lerp", + "image": { + "image_name": "canvas-mask.png" + } + } + } + }, + "outpaint_control_layer": { + "edges": [ + { + "destination": { + "field": "vae", + "node_id": "canvas_l2i" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "latents", + "node_id": "canvas_l2i" + }, + "source": { + "field": "latents", + "node_id": "denoise_latents" + } + }, + { + "destination": { + "field": "transformer", + "node_id": "denoise_latents" + }, + "source": { + "field": "transformer", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "vae", + "node_id": "denoise_latents" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "pos_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "pos_cond" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "positive_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "pos_cond" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "neg_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "neg_cond" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "negative_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "neg_cond" + } + }, + { + "destination": { + "field": "seed", + "node_id": "denoise_latents" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "seed", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "positive_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "negative_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "metadata", + "node_id": "canvas_output" + }, + "source": { + "field": "metadata", + "node_id": "core_metadata_0_i" + } + }, + { + "destination": { + "field": "mask2", + "node_id": "mask_combine" + }, + "source": { + "field": "image", + "node_id": "image_alpha_to_mask" + } + }, + { + "destination": { + "field": "image", + "node_id": "canvas_i2l" + }, + "source": { + "field": "image", + "node_id": "infill" + } + }, + { + "destination": { + "field": "vae", + "node_id": "canvas_i2l" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "latents", + "node_id": "denoise_latents" + }, + "source": { + "field": "latents", + "node_id": "canvas_i2l" + } + }, + { + "destination": { + "field": "mask", + "node_id": "create_gradient_mask" + }, + "source": { + "field": "image", + "node_id": "mask_combine" + } + }, + { + "destination": { + "field": "vae", + "node_id": "create_gradient_mask" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "denoise_mask", + "node_id": "denoise_latents" + }, + "source": { + "field": "denoise_mask", + "node_id": "create_gradient_mask" + } + }, + { + "destination": { + "field": "mask", + "node_id": "expand_mask" + }, + "source": { + "field": "expanded_mask_area", + "node_id": "create_gradient_mask" + } + }, + { + "destination": { + "field": "layer_upper", + "node_id": "canvas_output" + }, + "source": { + "field": "image", + "node_id": "canvas_l2i" + } + }, + { + "destination": { + "field": "mask", + "node_id": "canvas_output" + }, + "source": { + "field": "image", + "node_id": "expand_mask" + } + }, + { + "destination": { + "field": "image", + "node_id": "qwen_image_control_mask_q-control" + }, + "source": { + "field": "image", + "node_id": "mask_combine" + } + }, + { + "destination": { + "field": "inpaint_image", + "node_id": "qwen_image_control_q-control" + }, + "source": { + "field": "image", + "node_id": "infill" + } + }, + { + "destination": { + "field": "inpaint_mask", + "node_id": "qwen_image_control_q-control" + }, + "source": { + "field": "image", + "node_id": "qwen_image_control_mask_q-control" + } + }, + { + "destination": { + "field": "control", + "node_id": "denoise_latents" + }, + "source": { + "field": "control", + "node_id": "qwen_image_control_q-control" + } + } + ], + "id": "qwen_image_control_canvas_outpaint", + "nodes": { + "negative_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "negative_prompt", + "type": "string" + }, + "positive_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "positive_prompt", + "type": "string" + }, + "seed": { + "is_intermediate": true, + "use_cache": true, + "id": "seed", + "type": "integer" + }, + "model_loader": { + "is_intermediate": true, + "use_cache": true, + "id": "model_loader", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "type": "qwen_image_model_loader" + }, + "pos_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "pos_cond", + "type": "qwen_image_text_encoder" + }, + "neg_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "neg_cond", + "type": "qwen_image_text_encoder" + }, + "denoise_latents": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "height": 1024, + "id": "denoise_latents", + "steps": 40, + "type": "qwen_image_denoise", + "width": 768, + "denoising_start": 0.4, + "denoising_end": 1 + }, + "core_metadata_0_i": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "cfg_rescale_multiplier": 0, + "generation_mode": "qwen_image_outpaint", + "height": 1024, + "id": "core_metadata_0_i", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "rand_device": "cpu", + "seamless_x": false, + "seamless_y": false, + "steps": 40, + "type": "core_metadata", + "width": 768, + "qwen_image_quantization": "none", + "qwen_image_shift": "auto", + "clip_skip": 0, + "strength": 0.6 + }, + "infill": { + "is_intermediate": true, + "use_cache": true, + "id": "infill", + "type": "infill_lama", + "image": { + "image_name": "canvas-composite.png" + } + }, + "image_alpha_to_mask": { + "is_intermediate": true, + "use_cache": true, + "id": "image_alpha_to_mask", + "image": { + "image_name": "canvas-composite.png" + }, + "type": "tomask" + }, + "mask_combine": { + "is_intermediate": true, + "use_cache": true, + "id": "mask_combine", + "mask1": { + "image_name": "canvas-mask.png" + }, + "type": "mask_combine" + }, + "canvas_i2l": { + "is_intermediate": true, + "use_cache": true, + "id": "canvas_i2l", + "type": "qwen_image_i2l" + }, + "create_gradient_mask": { + "is_intermediate": true, + "use_cache": true, + "coherence_mode": "Gaussian Blur", + "edge_radius": 16, + "fp32": false, + "id": "create_gradient_mask", + "image": { + "image_name": "canvas-composite.png" + }, + "minimum_denoise": 0, + "type": "create_gradient_mask" + }, + "expand_mask": { + "is_intermediate": true, + "use_cache": true, + "fade_size_px": 16, + "id": "expand_mask", + "type": "expand_mask_with_fade" + }, + "canvas_l2i": { + "is_intermediate": true, + "use_cache": false, + "id": "canvas_l2i", + "type": "qwen_image_l2i" + }, + "canvas_output": { + "is_intermediate": true, + "use_cache": false, + "layer_base": { + "image_name": "canvas-composite.png" + }, + "type": "invokeai_img_blend", + "id": "canvas_output" + }, + "qwen_image_control_q-control": { + "is_intermediate": true, + "use_cache": true, + "begin_step_percent": 0, + "control_context_scale": 0.85, + "control_model": { + "base": "qwen-image", + "key": "qwen-union", + "name": "Qwen Image ControlNet Union", + "type": "controlnet", + "hash": "blake3:union" + }, + "end_step_percent": 1, + "id": "qwen_image_control_q-control", + "image": { + "image_name": "q-control.png" + }, + "type": "qwen_image_control" + }, + "qwen_image_control_mask_q-control": { + "is_intermediate": true, + "use_cache": true, + "id": "qwen_image_control_mask_q-control", + "max": 0, + "min": 255, + "type": "img_lerp" + } + } + }, + "txt2img_control_layer": { + "edges": [ + { + "destination": { + "field": "vae", + "node_id": "canvas_output" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "latents", + "node_id": "canvas_output" + }, + "source": { + "field": "latents", + "node_id": "denoise_latents" + } + }, + { + "destination": { + "field": "transformer", + "node_id": "denoise_latents" + }, + "source": { + "field": "transformer", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "vae", + "node_id": "denoise_latents" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "pos_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "pos_cond" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "positive_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "pos_cond" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "neg_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "neg_cond" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "negative_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "neg_cond" + } + }, + { + "destination": { + "field": "seed", + "node_id": "denoise_latents" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "seed", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "positive_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "negative_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "metadata", + "node_id": "canvas_output" + }, + "source": { + "field": "metadata", + "node_id": "core_metadata_0_i" + } + }, + { + "destination": { + "field": "control", + "node_id": "denoise_latents" + }, + "source": { + "field": "control", + "node_id": "qwen_image_control_q-control" + } + } + ], + "id": "qwen_image_control_canvas_txt2img", + "nodes": { + "negative_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "negative_prompt", + "type": "string" + }, + "positive_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "positive_prompt", + "type": "string" + }, + "seed": { + "is_intermediate": true, + "use_cache": true, + "id": "seed", + "type": "integer" + }, + "model_loader": { + "is_intermediate": true, + "use_cache": true, + "id": "model_loader", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "type": "qwen_image_model_loader" + }, + "pos_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "pos_cond", + "type": "qwen_image_text_encoder" + }, + "neg_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "neg_cond", + "type": "qwen_image_text_encoder" + }, + "denoise_latents": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "height": 1024, + "id": "denoise_latents", + "steps": 40, + "type": "qwen_image_denoise", + "width": 768 + }, + "canvas_output": { + "is_intermediate": true, + "use_cache": false, + "id": "canvas_output", + "type": "qwen_image_l2i" + }, + "core_metadata_0_i": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "cfg_rescale_multiplier": 0, + "generation_mode": "qwen_image_txt2img", + "height": 1024, + "id": "core_metadata_0_i", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "rand_device": "cpu", + "seamless_x": false, + "seamless_y": false, + "steps": 40, + "type": "core_metadata", + "width": 768, + "qwen_image_quantization": "none", + "qwen_image_shift": "auto", + "clip_skip": 0 + }, + "qwen_image_control_q-control": { + "is_intermediate": true, + "use_cache": true, + "begin_step_percent": 0, + "control_context_scale": 0.85, + "control_model": { + "base": "qwen-image", + "key": "qwen-union", + "name": "Qwen Image ControlNet Union", + "type": "controlnet", + "hash": "blake3:union" + }, + "end_step_percent": 1, + "id": "qwen_image_control_q-control", + "image": { + "image_name": "q-control.png" + }, + "type": "qwen_image_control" + } + } + } +} diff --git a/invokeai/frontend/webv2/src/features/generation/core/architectureCapabilities.test.ts b/invokeai/frontend/webv2/src/features/generation/core/architectureCapabilities.test.ts index 4a6bacb466d..d04352ee1c4 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/architectureCapabilities.test.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/architectureCapabilities.test.ts @@ -117,6 +117,7 @@ describe('the registry', () => { expect(getArchitectureFeatures('sd-1')?.control_kinds).toEqual(['controlnet', 't2i_adapter']); expect(getArchitectureFeatures('z-image')?.control_kinds).toEqual(['z_image_control']); + expect(getArchitectureFeatures('qwen-image')?.control_kinds).toEqual(['qwen_image_control']); expect(getArchitectureFeatures('made-up')).toBeUndefined(); }); diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts index 13b19bb86d3..82caeb025d7 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts @@ -76,6 +76,13 @@ describe('isControlKindSupportedForBase', () => { expect(isControlKindSupportedForBase('anima', 'controlnet')).toBe(false); }); + it('qwen_image_control is supported on qwen-image only, which supports nothing else', () => { + expect(isControlKindSupportedForBase('qwen-image', 'qwen_image_control')).toBe(true); + expect(isControlKindSupportedForBase('z-image', 'qwen_image_control')).toBe(false); + expect(isControlKindSupportedForBase('qwen-image', 'controlnet')).toBe(false); + expect(isControlKindSupportedForBase('qwen-image', 'z_image_control')).toBe(false); + }); + it('control_lora is supported on flux only', () => { expect(isControlKindSupportedForBase('flux', 'control_lora')).toBe(true); expect(isControlKindSupportedForBase('sd-1', 'control_lora')).toBe(false); @@ -348,6 +355,127 @@ describe('addControlLayers — Z-Image control', () => { }); }); +describe('addControlLayers — Qwen-Image control', () => { + const union = model('qwen-image', 'controlnet'); + const qwenLayer = (id: string, overrides: Partial = {}) => + layer({ + beginEndStepPct: [0, 1], + controlMode: null, + id, + imageName: `${id}.png`, + kind: 'qwen_image_control', + model: union, + weight: 0.85, + ...overrides, + }); + const inpaint = { image: { image_name: 'composite.png' }, mask: { image_name: 'canvas-mask.png' } }; + + it('creates the exact backend node and connects it directly to the Qwen-Image denoise', () => { + const graph = run({ + base: 'qwen-image', + layers: [qwenLayer('Q1', { beginEndStepPct: [0.2, 0.9], imageName: 'canny.png', weight: 0.7 })], + }); + + expect(graph.nodes.qwen_image_control_Q1).toEqual({ + begin_step_percent: 0.2, + control_context_scale: 0.7, + control_model: union, + end_step_percent: 0.9, + id: 'qwen_image_control_Q1', + image: { image_name: 'canny.png' }, + is_intermediate: true, + type: 'qwen_image_control', + use_cache: true, + }); + expect(graph.edges).toEqual([ + { + destination: { field: 'control', node_id: 'denoise_latents' }, + source: { field: 'control', node_id: 'qwen_image_control_Q1' }, + }, + ]); + // Without inpaint inputs the control image is all the node gets: no collector, no mask node. + expect(Object.keys(graph.nodes)).toEqual(['denoise_latents', 'qwen_image_control_Q1']); + }); + + it('feeds the inpaint image and the inverted canvas mask from fixed image fields', () => { + const graph = run({ base: 'qwen-image', inpaint, layers: [qwenLayer('Q1')] }); + + expect(graph.nodes.qwen_image_control_Q1).toMatchObject({ inpaint_image: { image_name: 'composite.png' } }); + // The canvas mask is white = keep; the node regenerates white, so 255 → 0 inverts it. + expect(graph.nodes.qwen_image_control_mask_Q1).toEqual({ + id: 'qwen_image_control_mask_Q1', + image: { image_name: 'canvas-mask.png' }, + is_intermediate: true, + max: 0, + min: 255, + type: 'img_lerp', + use_cache: true, + }); + expect(edgesTo(graph, 'qwen_image_control_Q1', 'inpaint_mask').map((edge) => edge.source)).toEqual([ + { field: 'image', node_id: 'qwen_image_control_mask_Q1' }, + ]); + expect(edgesTo(graph, 'qwen_image_control_Q1', 'inpaint_image')).toEqual([]); + }); + + it('feeds the inpaint image and mask through edges when nodes produce them', () => { + const graph = baseGraph(); + const resize = { id: 'resize', type: 'img_resize' }; + const combine = { id: 'combine', type: 'mask_combine' }; + graph.nodes.resize = resize; + graph.nodes.combine = combine; + addControlLayers(graph as never, { + base: 'qwen-image', + inpaint: { image: { field: 'image', node: resize }, mask: { field: 'image', node: combine } }, + layers: [qwenLayer('Q1')], + }); + + expect(graph.nodes.qwen_image_control_Q1).not.toHaveProperty('inpaint_image'); + expect(graph.nodes.qwen_image_control_mask_Q1).not.toHaveProperty('image'); + expect(edgesTo(graph, 'qwen_image_control_Q1', 'inpaint_image').map((edge) => edge.source)).toEqual([ + { field: 'image', node_id: 'resize' }, + ]); + expect(edgesTo(graph, 'qwen_image_control_mask_Q1', 'image').map((edge) => edge.source)).toEqual([ + { field: 'image', node_id: 'combine' }, + ]); + expect(edgesTo(graph, 'qwen_image_control_Q1', 'inpaint_mask').map((edge) => edge.source)).toEqual([ + { field: 'image', node_id: 'qwen_image_control_mask_Q1' }, + ]); + }); + + it('leaves the inpaint inputs to the kinds that condition on the region', () => { + const graph = run({ + base: 'z-image', + inpaint, + layers: [layer({ id: 'Z1', kind: 'z_image_control', model: model('z-image', 'controlnet') })], + }); + + expect(graph.nodes.z_image_control_Z1).not.toHaveProperty('inpaint_image'); + expect(Object.values(graph.nodes).some((node) => node.type === 'img_lerp')).toBe(false); + }); + + it('rejects a second Qwen-Image control because denoise accepts a single field', () => { + expect(() => run({ base: 'qwen-image', layers: [qwenLayer('Q1'), qwenLayer('Q2')] })).toThrow( + /qwen_image_control_limit/ + ); + }); + + it('rejects the control on the Edit variant, whose transformer the denoise refuses to control', () => { + expect(() => run({ base: 'qwen-image', layers: [qwenLayer('Q1')], modelVariant: 'edit' })).toThrow( + /qwen_image_edit_control/ + ); + }); + + it.each([ + [{ weight: -0.01 }, /invalid_adapter_values/], + [{ weight: 2.01 }, /invalid_adapter_values/], + [{ model: model('z-image', 'controlnet') }, /incompatible_base/], + [{ model: model('qwen-image', 'lora') }, /incompatible_adapter/], + [{ kind: 'controlnet' as const }, /switch_adapter_kind/], + ])('rejects %o', (overrides, reason) => { + expect(() => run({ base: 'qwen-image', layers: [qwenLayer('Q1', overrides)] })).toThrow(reason); + }); +}); + describe('addControlLayers — Anima ControlNet-LLLite', () => { const lllite = (key: string): ControlModelIdentifier => ({ base: 'anima', diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts index 4f7b689f1c1..9ed4549d6dd 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts @@ -45,14 +45,45 @@ export interface ControlLayerGraphInput { /** Kind support is separate from control-mode/model compatibility. */ export { isControlKindSupportedForBase } from './controlValidation'; +/** A node feeding an image input through an edge, or a fixed image field when no node produces it. */ +export type ImageSource = { node: BackendInvocationContract; field: string } | { image_name: string }; + +/** + * What the canvas inpaint and outpaint graphs regenerate: the image the denoise encodes, at processing size, and + * the canvas mask as uploaded (white = keep). Adapters that condition on the region read both. + */ +export interface CanvasInpaintSources { + image: ImageSource; + mask: ImageSource; +} + +/** Feeds `field` of `node` from `source`: an edge from the producing node, or the fixed image field. */ +const feedImage = ( + graph: BackendGraphContract, + node: BackendInvocationContract, + field: string, + source: ImageSource +): void => { + if ('node' in source) { + addEdge(graph, source.node, source.field, node, field); + } else { + node[field] = source; + } +}; + /** Options for {@link addControlLayers}. */ export interface AddControlLayersOptions { /** The main model base — selects the adapter nodes and support. */ base: SupportedGenerateBase; - /** The main model variant (a FLUX `dev_fill` blocks Control LoRA). */ + /** The main model variant (a FLUX `dev_fill` blocks Control LoRA; a Qwen-Image `edit` blocks its control). */ modelVariant?: string; /** The valid, resolved control layers to graft (in document order). */ layers: readonly ControlLayerGraphInput[]; + /** + * Present when the canvas compiles in inpaint or outpaint mode. The Qwen-Image control node also conditions on + * the inpainted region and takes them; the other kinds ignore them. + */ + inpaint?: CanvasInpaintSources; } /** @@ -77,7 +108,7 @@ const controlNetNodeType = (base: string): string => (base === 'flux' ? 'flux_co /** Validate defensively through the shared policy before graph wiring. */ export const addControlLayers = (graph: BackendGraphContract, options: AddControlLayersOptions): void => { - const { base, layers, modelVariant } = options; + const { base, inpaint, layers, modelVariant } = options; const denoise = graph.nodes[CONTROL_DENOISE_NODE_ID]; if (!denoise) { throw new Error('addControlLayers: base graph is missing the denoise node.'); @@ -161,6 +192,31 @@ export const addControlLayers = (graph: BackendGraphContract, options: AddContro weight: layer.weight, }); addEdge(graph, node, 'control', getOrAddLliteCollector(graph, denoise), 'item'); + } else if (layer.kind === 'qwen_image_control') { + // One field on the denoise, no collector: validation admits a single Qwen-Image control per generation. + const node = addNode(graph, { + begin_step_percent: layer.beginEndStepPct[0], + control_context_scale: layer.weight, + control_model: layer.model, + end_step_percent: layer.beginEndStepPct[1], + id: `qwen_image_control_${layer.id}`, + image: { image_name: layer.imageName }, + type: 'qwen_image_control', + }); + if (inpaint) { + // The union's inpainting condition. The canvas mask is white = keep and the node wants white = regenerate, + // so `img_lerp` 255 → 0 inverts it first, as the Anima inpaint adapter does. + const invertMask = addNode(graph, { + id: `qwen_image_control_mask_${layer.id}`, + max: 0, + min: 255, + type: 'img_lerp', + }); + feedImage(graph, invertMask, 'image', inpaint.mask); + feedImage(graph, node, 'inpaint_image', inpaint.image); + addEdge(graph, invertMask, 'image', node, 'inpaint_mask'); + } + addEdge(graph, node, 'control', denoise, 'control'); } else { const node = addNode(graph, { begin_step_percent: layer.beginEndStepPct[0], diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts index 433f8e0fe94..11218061889 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts @@ -930,6 +930,157 @@ describe('compileCanvasGraph — control layers (integration)', () => { }); }); +describe('compileCanvasGraph — Qwen-Image ControlNet (integration)', () => { + const layer: ControlLayerGraphInput = { + beginEndStepPct: [0, 1], + controlMode: null, + id: 'q-control', + imageName: 'q-control.png', + kind: 'qwen_image_control', + model: { base: 'qwen-image', key: 'qwen-union', name: 'Qwen Image ControlNet Union', type: 'controlnet' }, + weight: 0.85, + }; + const CONTROL = 'qwen_image_control_q-control'; + const MASK = 'qwen_image_control_mask_q-control'; + const edgesInto = (graph: BackendGraphContract, nodeId: string) => + graph.edges + .filter((edge) => edge.destination.node_id === nodeId) + .map((edge) => [edge.destination.field, edge.source]); + + it('grafts the control into the Qwen-Image base graph, whose denoise holds the VAE that encodes its images', () => { + const { backendGraph } = compile(qwenImageModel, 'txt2img', { controlLayers: [layer] }); + + expect(backendGraph.nodes.denoise_latents?.type).toBe('qwen_image_denoise'); + expect(backendGraph.nodes[CONTROL]).toMatchObject({ + begin_step_percent: 0, + control_context_scale: 0.85, + control_model: layer.model, + end_step_percent: 1, + image: { image_name: 'q-control.png' }, + type: 'qwen_image_control', + }); + expect(getEdge(backendGraph, 'denoise_latents', 'control')?.source).toEqual({ field: 'control', node_id: CONTROL }); + expect(getEdge(backendGraph, 'denoise_latents', 'vae')?.source).toEqual({ field: 'vae', node_id: 'model_loader' }); + }); + + it.each(['txt2img', 'img2img'] as const)('sends only the control image in %s', (mode) => { + const { backendGraph } = compile(qwenImageModel, mode, { controlLayers: [layer] }); + + expect(backendGraph.nodes[CONTROL]).not.toHaveProperty('inpaint_image'); + expect(edgesInto(backendGraph, CONTROL)).toEqual([]); + expect(backendGraph.nodes[MASK]).toBeUndefined(); + }); + + it('inpaint: the control also reads the composite and the inverted canvas mask the denoise is limited to', () => { + const { backendGraph } = compile(qwenImageModel, 'inpaint', { controlLayers: [layer] }); + + expect(backendGraph.nodes[CONTROL]).toMatchObject({ inpaint_image: { image_name: 'canvas-composite.png' } }); + // The canvas mask is white = keep; img_lerp 255 → 0 makes it white = regenerate for the control. + expect(backendGraph.nodes[MASK]).toEqual({ + id: MASK, + image: { image_name: 'canvas-mask.png' }, + is_intermediate: true, + max: 0, + min: 255, + type: 'img_lerp', + use_cache: true, + }); + expect(edgesInto(backendGraph, CONTROL)).toEqual([['inpaint_mask', { field: 'image', node_id: MASK }]]); + // The denoise mask is untouched: the gradient mask still reads the uploaded canvas mask as is. + expect(backendGraph.nodes.create_gradient_mask?.mask).toEqual({ image_name: 'canvas-mask.png' }); + expect(getEdge(backendGraph, 'denoise_latents', 'denoise_mask')?.source.node_id).toBe('create_gradient_mask'); + }); + + it('inpaint with Scale Before Processing: the control reads the resized composite and mask', () => { + const { backendGraph } = compile(qwenImageModel, 'inpaint', { + bbox: { height: 888, width: 1025, x: 0, y: 0 }, + controlLayers: [layer], + }); + + expect(backendGraph.nodes[CONTROL]).not.toHaveProperty('inpaint_image'); + expect(backendGraph.nodes[MASK]).not.toHaveProperty('image'); + expect(getEdge(backendGraph, CONTROL, 'inpaint_image')?.source.node_id).toBe('canvas_resize_initial_to_processing'); + expect(getEdge(backendGraph, MASK, 'image')?.source.node_id).toBe('canvas_resize_mask_to_processing'); + }); + + it('inpaint with a noise mask: the control reads the image before noise is added', () => { + const { backendGraph } = compile(qwenImageModel, 'inpaint', { + controlLayers: [layer], + noiseMaskImageName: 'noise.png', + }); + + expect(getEdge(backendGraph, 'canvas_i2l', 'image')?.source.node_id).toBe('add_inpaint_noise'); + expect(backendGraph.nodes[CONTROL]).toMatchObject({ inpaint_image: { image_name: 'canvas-composite.png' } }); + }); + + it('outpaint: the control reads the infilled image and the alpha-derived or combined mask', () => { + const alphaOnly = compile(qwenImageModel, 'outpaint', { controlLayers: [layer], maskImageName: null }).backendGraph; + expect(getEdge(alphaOnly, CONTROL, 'inpaint_image')?.source.node_id).toBe('infill'); + expect(getEdge(alphaOnly, MASK, 'image')?.source.node_id).toBe('image_alpha_to_mask'); + expect(getEdge(alphaOnly, CONTROL, 'inpaint_mask')?.source.node_id).toBe(MASK); + + const combined = compile(qwenImageModel, 'outpaint', { + controlLayers: [layer], + maskImageName: 'canvas-mask.png', + }).backendGraph; + expect(getEdge(combined, MASK, 'image')?.source.node_id).toBe('mask_combine'); + + const scaled = compile(qwenImageModel, 'outpaint', { + bbox: { height: 888, width: 1025, x: 0, y: 0 }, + controlLayers: [layer], + maskImageName: null, + }).backendGraph; + expect(getEdge(scaled, MASK, 'image')?.source.node_id).toBe('canvas_resize_outpaint_mask_to_processing'); + expect(getEdge(scaled, CONTROL, 'inpaint_image')?.source.node_id).toBe('infill'); + }); + + it('rejects the control on a Qwen Image Edit model, as the denoise does', () => { + expect(() => compile({ ...qwenImageModel, variant: 'edit' }, 'inpaint', { controlLayers: [layer] })).toThrow( + /qwen_image_edit_control/ + ); + }); + + it('leaves inpainting without a control layer as it was', () => { + const { backendGraph } = compile(qwenImageModel, 'inpaint'); + + expect(Object.values(backendGraph.nodes).map((node) => node.type)).not.toContain('img_lerp'); + expect(Object.values(backendGraph.nodes).map((node) => node.type)).not.toContain('qwen_image_control'); + }); + + it('writes the graphs the backend validates against its invocations', async () => { + // Ids minted from the clock and Math.random are pinned so the fixture changes only when the graph does. + const clock = vi.spyOn(Date, 'now').mockReturnValue(0); + const random = vi.spyOn(Math, 'random').mockReturnValue(0.5); + // Installed models always carry a hash, which the backend's model identifier requires. + const hashed = (config: T, hash: string): T => ({ ...config, hash }); + const model = hashed(qwenImageModel, 'blake3:qwen'); + const controlLayers = [{ ...layer, model: hashed(layer.model, 'blake3:union') }]; + let txt2img: BackendGraphContract; + let inpaint: BackendGraphContract; + let outpaint: BackendGraphContract; + try { + txt2img = compile(model, 'txt2img', { controlLayers }).backendGraph; + // Without Scale Before Processing the control reads the canvas uploads as fixed image fields. + inpaint = compile(model, 'inpaint', { controlLayers }).backendGraph; + // The infilled image and the combined mask reach the control through edges. + outpaint = compile(model, 'outpaint', { controlLayers, maskImageName: 'canvas-mask.png' }).backendGraph; + } finally { + clock.mockRestore(); + random.mockRestore(); + } + const fixture = { + _comment: + 'Generated by compileCanvasGraph.test.ts; regenerate with `vitest -u`. Consumed by tests/app/invocations/test_frontend_qwen_image_control_graphs.py, which validates the graphs against the backend invocations.', + inpaint_control_layer: { ...inpaint, id: 'qwen_image_control_canvas_inpaint' }, + outpaint_control_layer: { ...outpaint, id: 'qwen_image_control_canvas_outpaint' }, + txt2img_control_layer: { ...txt2img, id: 'qwen_image_control_canvas_txt2img' }, + }; + await expect(`${JSON.stringify(fixture, null, 2)}\n`).toMatchFileSnapshot( + '../__snapshots__/qwenImageControlCanvasGraphs.json' + ); + }); +}); + describe('compileCanvasGraph — Anima ControlNet-LLLite (integration)', () => { const lliteLayer = (id: string, key: string, weight = 1): ControlLayerGraphInput => ({ beginEndStepPct: [0, 0.9], diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.ts index 4260197de7f..5422069aff1 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.ts @@ -21,6 +21,7 @@ import { getIsPidActive } from '@features/generation/core/pid'; import { shouldUsePidDecode } from '@features/generation/core/pidGraph'; import { MAX_ANIMA_INPAINT_ADAPTER_WEIGHT, MIN_ANIMA_INPAINT_ADAPTER_WEIGHT } from '@features/generation/core/settings'; +import type { CanvasInpaintSources } from './addControlLayers'; import type { CanvasCompositingSettings, CanvasInfillMethod, @@ -67,9 +68,6 @@ const isImageMode = (mode: CompileCanvasGraphInput['mode']): boolean => mode !== const sizesMatch = (left: CanvasSize, right: CanvasSize): boolean => left.width === right.width && left.height === right.height; -/** A node feeding an input through an edge, or a fixed image field when no node produces it. */ -type ImageSource = { node: BackendInvocationContract; field: string } | { image_name: string }; - /** Whether an Anima inpaint/outpaint graph gets the adapter: it is picked, and the base is Anima. */ const hasAnimaInpaintAdapter = (model: GenerateModelConfig, settings: GenerateSettings): boolean => model.base === 'anima' && settings.animaInpaintAdapterModel !== null; @@ -370,13 +368,13 @@ const addAnimaInpaintAdapter = ( graph: BackendGraphContract, args: { denoise: BackendInvocationContract; - image: ImageSource; - mask: ImageSource; + inpaint: CanvasInpaintSources; model: ComponentModelConfig; weight: number; } ): void => { - const { denoise, image, mask, model, weight } = args; + const { denoise, inpaint, model, weight } = args; + const { image, mask } = inpaint; const invertMask = addNode(graph, { id: 'invert_anima_inpaint_adapter_mask', ...('image_name' in mask ? { image: mask } : {}), @@ -408,7 +406,10 @@ const addAnimaInpaintAdapter = ( } }; -/** outputOnlyMaskedRegions selects transparent output versus compositing with the original. */ +/** + * outputOnlyMaskedRegions selects transparent output versus compositing with the original. Returns what the + * inpaint-conditioned adapters read. + */ const graftMaskTail = ( graph: BackendGraphContract, args: { @@ -426,10 +427,10 @@ const graftMaskTail = ( /** Either a fixed mask image field or an edge-fed source node. */ gradientMaskImage?: { image_name: string }; gradientMaskEdge?: { node: BackendInvocationContract; field: string }; - /** The raster image the Anima inpaint adapter conditions on; the composite itself when absent. */ + /** The raster image the inpaint-conditioned adapters read; the composite itself when absent. */ adapterImageEdge?: { node: BackendInvocationContract; field: string }; } -): void => { +): CanvasInpaintSources => { const { compositing, denoise, destination, i2lType, initialImageName, model, settings, vaeSource } = args; const needsResize = !sizesMatch(args.bbox, args.processingSize); @@ -464,11 +465,15 @@ const graftMaskTail = ( } addEdge(graph, gradientMask, 'denoise_mask', denoise, 'denoise_mask'); + // The image before any noise is added, and the mask the denoise limits itself to, both at processing size. + const inpaint: CanvasInpaintSources = { + image: args.adapterImageEdge ?? { image_name: initialImageName }, + mask: args.gradientMaskEdge ?? (args.gradientMaskImage as { image_name: string }), + }; if (hasAnimaInpaintAdapter(model, settings)) { addAnimaInpaintAdapter(graph, { denoise, - image: args.adapterImageEdge ?? { image_name: initialImageName }, - mask: args.gradientMaskEdge ?? (args.gradientMaskImage as { image_name: string }), + inpaint, model: settings.animaInpaintAdapterModel as ComponentModelConfig, weight: settings.animaInpaintAdapterWeight, }); @@ -522,6 +527,7 @@ const graftMaskTail = ( ); addEdge(graph, generatedImageSource, 'image', output, compositing.outputOnlyMaskedRegions ? 'image' : 'layer_upper'); addEdge(graph, outputMaskSource, 'image', output, 'mask'); + return inpaint; }; /** Optionally inserts an `img_noise` node before encode; returns the node feeding `i2l.image`. */ @@ -561,7 +567,7 @@ const graftInpaint = ( input: CompileCanvasGraphInput, compositing: CanvasCompositingSettings, processingSize: CanvasSize -): void => { +): CanvasInpaintSources => { const { model } = input; const i2lType = requireI2lType(model); const denoise = requireDenoise(graph); @@ -601,7 +607,7 @@ const graftInpaint = ( addEdge(graph, vaeSource.node, vaeSource.field, encode, 'vae'); addEdge(graph, encode, 'latents', denoise, 'latents'); - graftMaskTail(graph, { + const inpaint = graftMaskTail(graph, { ...(initialResize ? { adapterImageEdge: { field: 'image', node: initialResize } } : {}), bbox: input.bbox, compositing, @@ -620,6 +626,7 @@ const graftInpaint = ( }); setMetadataMode(graph, 'inpaint', strength); + return inpaint; }; /** Grafts the outpaint pipeline (bbox extends past content / has transparent holes). */ @@ -628,7 +635,7 @@ const graftOutpaint = ( input: CompileCanvasGraphInput, compositing: CanvasCompositingSettings, processingSize: CanvasSize -): void => { +): CanvasInpaintSources => { const { model } = input; const i2lType = requireI2lType(model); const denoise = requireDenoise(graph); @@ -697,7 +704,7 @@ const graftOutpaint = ( addEdge(graph, vaeSource.node, vaeSource.field, encode, 'vae'); addEdge(graph, encode, 'latents', denoise, 'latents'); - graftMaskTail(graph, { + const inpaint = graftMaskTail(graph, { adapterImageEdge: { field: 'image', node: infill }, bbox: input.bbox, compositing, @@ -714,6 +721,7 @@ const graftOutpaint = ( }); setMetadataMode(graph, 'outpaint', strength); + return inpaint; }; /** Throw the first validation reason. */ @@ -747,18 +755,21 @@ export const compileCanvasGraph = (input: CompileCanvasGraphInput): CompiledCanv const { compositing } = input; // Validation above guarantees the composite/mask images required per mode. + let inpaint: CanvasInpaintSources | undefined; if (mode === 'img2img') { graftImageToImage(backendGraph, model, settings, compositeImageName as string, strength, bbox); } else if (mode === 'inpaint') { - graftInpaint(backendGraph, input, compositing, processingSize); + inpaint = graftInpaint(backendGraph, input, compositing, processingSize); } else if (mode === 'outpaint') { - graftOutpaint(backendGraph, input, compositing, processingSize); + inpaint = graftOutpaint(backendGraph, input, compositing, processingSize); } - // Every mode accepts already-resolved, separately uploaded control inputs. + // Every mode accepts already-resolved, separately uploaded control inputs; inpaint and outpaint also hand the + // adapters what they regenerate. if (input.controlLayers && input.controlLayers.length > 0) { addControlLayers(backendGraph, { base: model.base as SupportedGenerateBase, + inpaint, layers: input.controlLayers, modelVariant: model.variant ?? undefined, }); diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.test.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.test.ts index a337ed16150..c8b915a92b7 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.test.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.test.ts @@ -95,6 +95,33 @@ describe('getControlValidationReason', () => { ).toBe('z_image_control_limit'); }); + it('accepts only a Qwen-Image ControlNet model on a Qwen-Image generation model', () => { + const qwen = { + adapterModel: { base: 'qwen-image', type: 'controlnet' }, + beginEndStepPct: [0, 1] as [number, number], + controlLoraIndex: 0, + kind: 'qwen_image_control' as const, + mainBase: 'qwen-image', + weight: 0.85, + }; + expect(getControlValidationReason(qwen)).toBeNull(); + expect(getControlValidationReason({ ...qwen, mainVariant: 'edit' })).toBe('qwen_image_edit_control'); + expect(getControlValidationReason({ ...qwen, qwenImageControlIndex: 1 })).toBe('qwen_image_control_limit'); + expect(getControlValidationReason({ ...qwen, mainBase: 'z-image' })).toBe('switch_adapter_kind'); + expect(getControlValidationReason({ ...qwen, kind: 'controlnet' })).toBe('switch_adapter_kind'); + expect(getControlValidationReason({ ...qwen, adapterModel: { base: 'z-image', type: 'controlnet' } })).toBe( + 'incompatible_base' + ); + expect(getControlValidationReason({ ...qwen, adapterModel: { base: 'qwen-image', type: 'lora' } })).toBe( + 'incompatible_adapter' + ); + // The node's context scale is 0..2; the legacy -1 floor does not apply. + expect(getControlValidationReason({ ...qwen, weight: 0 })).toBeNull(); + expect(getControlValidationReason({ ...qwen, weight: 2 })).toBeNull(); + expect(getControlValidationReason({ ...qwen, weight: -0.01 })).toBe('invalid_adapter_values'); + expect(getControlValidationReason({ ...qwen, weight: 2.01 })).toBe('invalid_adapter_values'); + }); + it.each([ { beginEndStepPct: [0, 1] as [number, number], kind: 'controlnet' as const, weight: Number.NaN }, { beginEndStepPct: [0, 1] as [number, number], kind: 'controlnet' as const, weight: Number.POSITIVE_INFINITY }, @@ -172,6 +199,7 @@ describe('Anima ControlNet-LLLite validation', () => { it('suggests the kind each base runs, preferring ControlNet, and none where control layers are unsupported', () => { expect(getSuggestedControlKind('anima')).toBe('anima_lllite'); expect(getSuggestedControlKind('z-image')).toBe('z_image_control'); + expect(getSuggestedControlKind('qwen-image')).toBe('qwen_image_control'); expect(getSuggestedControlKind('flux')).toBe('controlnet'); expect(getSuggestedControlKind('sd-2')).toBeNull(); expect(getControlValidationReason({ ...lllite, mainBase: 'sd-2' })).toBe('unsupported_adapter'); @@ -253,4 +281,21 @@ describe('createControlValidationSequence', () => { }) ).toBe('flux_fill_control_lora'); }); + + it('lets one Qwen-Image control through per generation, and none on an Edit model', () => { + const qwen = { + adapterModel: { base: 'qwen-image', key: 'union', type: 'controlnet' }, + beginEndStepPct: [0, 1] as [number, number], + kind: 'qwen_image_control' as const, + weight: 0.85, + }; + const generate = createControlValidationSequence({ base: 'qwen-image' }); + expect(generate(qwen)).toBeNull(); + expect(generate(qwen)).toBe('qwen_image_control_limit'); + + // A refused layer claims no slot, so every layer on an Edit model reports the same reason. + const edit = createControlValidationSequence({ base: 'qwen-image', variant: 'edit' }); + expect(edit(qwen)).toBe('qwen_image_edit_control'); + expect(edit(qwen)).toBe('qwen_image_edit_control'); + }); }); diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts index 95957ea238d..90088e0761e 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts @@ -10,6 +10,7 @@ export const CONTROL_ADAPTER_KINDS = [ 'control_lora', 'z_image_control', 'anima_lllite', + 'qwen_image_control', ] as const; export type ControlAdapterKind = (typeof CONTROL_ADAPTER_KINDS)[number]; @@ -26,8 +27,10 @@ export const CONTROL_VALIDATION_REASONS = [ 'invalid_adapter_values', 'control_lora_limit', 'z_image_control_limit', + 'qwen_image_control_limit', 'duplicate_lllite_model', 'flux_fill_control_lora', + 'qwen_image_edit_control', ] as const; export type ControlValidationReason = (typeof CONTROL_VALIDATION_REASONS)[number]; @@ -39,9 +42,16 @@ export interface ControlAdapterModelFacts { cond_in_channels?: number | null; } -/** Z-Image control and Anima ControlNet-LLLite models install with the `controlnet` model type. */ +/** Z-Image control, Anima ControlNet-LLLite and Qwen-Image control models install with the `controlnet` model type. */ const getControlAdapterModelType = (kind: ControlAdapterKind): string => - kind === 'z_image_control' || kind === 'anima_lllite' ? 'controlnet' : kind; + kind === 'z_image_control' || kind === 'anima_lllite' || kind === 'qwen_image_control' ? 'controlnet' : kind; + +/** + * The lowest weight a kind accepts: the Z-Image and Qwen-Image control nodes take a 0..2 context scale, the other + * adapters keep the legacy -1 floor. Validation, persisted-value repair and the weight input share it. + */ +export const getControlAdapterMinWeight = (kind: ControlAdapterKind): number => + kind === 'z_image_control' || kind === 'qwen_image_control' ? 0 : -1; /** The backend owns kind support; count and Fill constraints are frontend policy. */ export const isControlKindSupportedForBase = (base: string, kind: ControlAdapterKind): boolean => @@ -98,6 +108,7 @@ export const getControlValidationReason = (params: { mainVariant?: string; weight: number; zImageControlIndex?: number; + qwenImageControlIndex?: number; /** An earlier contributing Anima LLLite layer already applies this model; the denoiser applies each once. */ lliteModelInUse?: boolean; }): ControlValidationReason | null => { @@ -109,6 +120,7 @@ export const getControlValidationReason = (params: { lliteModelInUse = false, mainBase, mainVariant, + qwenImageControlIndex = 0, weight, zImageControlIndex = 0, } = params; @@ -141,22 +153,32 @@ export const getControlValidationReason = (params: { if (kind === 'z_image_control' && zImageControlIndex > 0) { return 'z_image_control_limit'; } + if (kind === 'qwen_image_control' && qwenImageControlIndex > 0) { + return 'qwen_image_control_limit'; + } if (kind === 'anima_lllite' && lliteModelInUse) { return 'duplicate_lllite_model'; } if (kind === 'control_lora' && mainBase === 'flux' && mainVariant === 'dev_fill') { return 'flux_fill_control_lora'; } + if (kind === 'qwen_image_control' && mainBase === 'qwen-image' && mainVariant === 'edit') { + // The Fun-ControlNet branch was trained beside the generation transformer; `qwen_image_denoise` refuses it on + // an Edit transformer. + return 'qwen_image_edit_control'; + } return null; }; /** - * Validates control layers in generation order. Per-generation limits (one Control LoRA, one Z-Image control, each - * LLLite model once) count only layers that passed, so an invalid layer never consumes a later layer's slot. + * Validates control layers in generation order. Per-generation limits (one Control LoRA, one Z-Image control, one + * Qwen-Image control, each LLLite model once) count only layers that passed, so an invalid layer never consumes a + * later layer's slot. */ export const createControlValidationSequence = (main: { base: string; variant?: string | null }) => { let controlLoraCount = 0; let zImageControlCount = 0; + let qwenImageControlCount = 0; const lliteModelKeys = new Set(); return (layer: { @@ -174,6 +196,7 @@ export const createControlValidationSequence = (main: { base: string; variant?: lliteModelInUse: kind === 'anima_lllite' && adapterModel !== null && lliteModelKeys.has(adapterModel.key), mainBase: main.base, mainVariant: main.variant ?? undefined, + qwenImageControlIndex: kind === 'qwen_image_control' ? qwenImageControlCount : 0, weight: layer.weight, zImageControlIndex: kind === 'z_image_control' ? zImageControlCount : 0, }); @@ -184,6 +207,8 @@ export const createControlValidationSequence = (main: { base: string; variant?: controlLoraCount += 1; } else if (kind === 'z_image_control') { zImageControlCount += 1; + } else if (kind === 'qwen_image_control') { + qwenImageControlCount += 1; } else if (kind === 'anima_lllite' && adapterModel) { lliteModelKeys.add(adapterModel.key); } @@ -197,7 +222,7 @@ export const areControlAdapterValuesValid = ( weight: unknown, beginEndStepPct: unknown ): beginEndStepPct is [number, number] => { - const minWeight = kind === 'z_image_control' ? 0 : -1; + const minWeight = getControlAdapterMinWeight(kind); if (typeof weight !== 'number' || !Number.isFinite(weight) || weight < minWeight || weight > 2) { return false; } diff --git a/invokeai/frontend/webv2/src/features/generation/core/graph.test.ts b/invokeai/frontend/webv2/src/features/generation/core/graph.test.ts index 4a97ab2594f..3416d582ba3 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/graph.test.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/graph.test.ts @@ -448,6 +448,13 @@ describe('compileGenerateGraph', () => { expect(compile(zImageModel).nodes.model_loader?.type).toBe('z_image_model_loader'); }); + it('hands the Qwen Image denoise the loader VAE its ControlNet encodes with', () => { + expect(getEdge(compile(qwenImageModel), 'denoise_latents', 'vae')?.source).toEqual({ + field: 'vae', + node_id: 'model_loader', + }); + }); + it('builds complete SDNQ pipeline graphs without standalone component overrides', () => { const flux = compile({ ...fluxModel, diff --git a/invokeai/frontend/webv2/src/features/generation/core/graph.ts b/invokeai/frontend/webv2/src/features/generation/core/graph.ts index 13009af1045..5916142ad1e 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/graph.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/graph.ts @@ -1016,6 +1016,8 @@ const buildQwenImageGraph = ( }); addEdge(graph, loraSource, 'transformer', denoise, 'transformer'); + // The denoise encodes a ControlNet's control and inpaint images with this VAE; without one the input is idle. + addEdge(graph, modelLoader, 'vae', denoise, 'vae'); addEdge(graph, modelLoader, 'qwen_vl_encoder', posCond, 'qwen_vl_encoder'); addEdge(graph, positivePrompt, 'value', posCond, 'prompt'); addEdge(graph, posCond, 'conditioning', denoise, 'positive_conditioning'); diff --git a/invokeai/frontend/webv2/src/features/generation/graph.ts b/invokeai/frontend/webv2/src/features/generation/graph.ts index b29991d4d7a..c09d5da43e6 100644 --- a/invokeai/frontend/webv2/src/features/generation/graph.ts +++ b/invokeai/frontend/webv2/src/features/generation/graph.ts @@ -22,6 +22,7 @@ export { type ControlAdapterKind, type ControlValidationReason, createControlValidationSequence, + getControlAdapterMinWeight, getControlModelUnusableReason, getControlValidationReason, getSuggestedControlKind, diff --git a/invokeai/frontend/webv2/src/workbench/canvas-engine/contracts.ts b/invokeai/frontend/webv2/src/workbench/canvas-engine/contracts.ts index 1b6ffd010d5..c85511d5ae5 100644 --- a/invokeai/frontend/webv2/src/workbench/canvas-engine/contracts.ts +++ b/invokeai/frontend/webv2/src/workbench/canvas-engine/contracts.ts @@ -234,7 +234,7 @@ export type CanvasAdjustmentEntry = export type CanvasAdjustmentsContract = readonly CanvasAdjustmentEntry[]; export interface CanvasControlAdapterContract { - kind: 'controlnet' | 't2i_adapter' | 'control_lora' | 'z_image_control' | 'anima_lllite'; + kind: 'controlnet' | 't2i_adapter' | 'control_lora' | 'z_image_control' | 'anima_lllite' | 'qwen_image_control'; model: string | null; weight: number; beginEndStepPct: [number, number]; diff --git a/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.test.ts b/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.test.ts index cc368657eee..6664e2703fd 100644 --- a/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.test.ts +++ b/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.test.ts @@ -31,6 +31,7 @@ const EXPECTED_DEFAULTS: Record> = { spandrel_filter: { model: null, autoScale: true, scale: 1 }, img_blur: { blur_type: 'gaussian', radius: 8 }, img_noise: { noise_type: 'gaussian', amount: 0.3, noise_color: true, size: 1 }, + grayscale: {}, }; const EXPECTED_TYPES = Object.keys(EXPECTED_DEFAULTS); @@ -43,10 +44,10 @@ const SPANDREL_MODEL = { }; describe('CONTROL_FILTERS registry', () => { - it('contains the legacy filters plus the Scribble preset', () => { + it('contains the legacy filters plus the Scribble preset and Grayscale', () => { const types = CONTROL_FILTERS.map((definition) => definition.type); - expect(types).toHaveLength(17); - expect(new Set(types).size).toBe(17); + expect(types).toHaveLength(18); + expect(new Set(types).size).toBe(18); expect(types).toEqual(EXPECTED_TYPES); }); @@ -145,7 +146,10 @@ describe('buildFilterGraph', () => { it('builds the direct legacy filter nodes with default params', () => { const directTypes = EXPECTED_TYPES.filter( - (type) => !['adjust_image', 'spandrel_filter', 'img_blur', 'img_noise', 'scribble_edge_detection'].includes(type) + (type) => + !['adjust_image', 'spandrel_filter', 'img_blur', 'img_noise', 'scribble_edge_detection', 'grayscale'].includes( + type + ) ); for (const type of directTypes) { const { graph, outputNodeId } = buildFilterGraph(type, imageName); @@ -183,6 +187,49 @@ describe('buildFilterGraph', () => { expect(outputNodeId).toBe(FILTER_NODE_ID); }); + it('builds Grayscale as a mode round trip, so the layer stays RGB', () => { + const { graph, outputNodeId } = buildFilterGraph('grayscale', imageName); + + expect(graph.nodes[FILTER_NODE_ID]).toMatchObject({ + image: { image_name: imageName }, + mode: 'L', + type: 'img_conv', + }); + expect(graph.nodes.control_filter_rgb).toEqual({ + id: 'control_filter_rgb', + is_intermediate: true, + mode: 'RGB', + type: 'img_conv', + use_cache: true, + }); + expect(graph.edges).toEqual([ + { + destination: { field: 'image', node_id: 'control_filter_rgb' }, + source: { field: 'image', node_id: FILTER_NODE_ID }, + }, + ]); + expect(outputNodeId).toBe('control_filter_rgb'); + }); + + it('restores the source alpha onto the Grayscale result, not onto the intermediate L image', () => { + const { graph, outputNodeId } = buildFilterGraph('grayscale', imageName, undefined, { + height: 8, + preserveTransparency: true, + width: 8, + }); + + expect(graph.nodes[FILTER_NODE_ID]).not.toHaveProperty('image'); + expect(graph.edges).toContainEqual({ + destination: { field: 'image', node_id: FILTER_NODE_ID }, + source: { field: 'image', node_id: 'control_filter_flatten' }, + }); + expect(graph.edges).toContainEqual({ + destination: { field: 'image', node_id: 'control_filter_restore_alpha' }, + source: { field: 'image', node_id: 'control_filter_rgb' }, + }); + expect(outputNodeId).toBe('control_filter_restore_alpha'); + }); + it('flattens transparent control inputs over white before processing and reapplies their alpha', () => { const { graph, outputNodeId } = buildFilterGraph('canny_edge_detection', imageName, undefined, { height: 80, diff --git a/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.ts b/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.ts index d9dfa0187cf..863dfbb17a8 100644 --- a/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.ts +++ b/invokeai/frontend/webv2/src/workbench/canvas-operations/filterGraphs.ts @@ -221,6 +221,13 @@ export const CONTROL_FILTERS: readonly FilterDefinition[] = [ category: 'noise', type: 'img_noise', }, + { + // The Qwen-Image Fun-ControlNet-Union's "Gray" condition: `img_conv` to L and back, so the layer stays RGB. + category: 'color', + nodeType: 'img_conv', + params: [], + type: 'grayscale', + }, ]; const FILTERS_BY_TYPE: ReadonlyMap = new Map( @@ -354,6 +361,8 @@ export const buildFilterGraph = ( source: { field: sourceField, node_id: sourceId }, }); }; + // The node whose image is the filter's result; a multi-node filter moves it past the filter node. + let outputNodeId: string = FILTER_NODE_ID; if (filterType === 'scribble_edge_detection') { graph.nodes[FILTER_NODE_ID] = { ...node, scribble: true }; @@ -434,6 +443,17 @@ export const buildFilterGraph = ( use_cache: false, }; edge('control_filter_seed', 'value', FILTER_NODE_ID, 'seed'); + } else if (filterType === 'grayscale') { + graph.nodes[FILTER_NODE_ID] = { ...node, mode: 'L' }; + graph.nodes.control_filter_rgb = { + id: 'control_filter_rgb', + is_intermediate: true, + mode: 'RGB', + type: 'img_conv', + use_cache: true, + }; + edge(FILTER_NODE_ID, 'image', 'control_filter_rgb', 'image'); + outputNodeId = 'control_filter_rgb'; } const canRestoreSourceAlpha = @@ -482,13 +502,10 @@ export const buildFilterGraph = ( }; edge('control_filter_background', 'image', 'control_filter_flatten', 'base_image'); edge('control_filter_flatten', 'image', FILTER_NODE_ID, 'image'); - edge(FILTER_NODE_ID, 'image', 'control_filter_restore_alpha', 'image'); + edge(outputNodeId, 'image', 'control_filter_restore_alpha', 'image'); edge('control_filter_source_alpha', 'image', 'control_filter_restore_alpha', 'mask'); return { graph, outputNodeId: 'control_filter_restore_alpha' }; } - return { - graph, - outputNodeId: FILTER_NODE_ID, - }; + return { graph, outputNodeId }; }; diff --git a/invokeai/frontend/webv2/src/workbench/canvasMigration.test.ts b/invokeai/frontend/webv2/src/workbench/canvasMigration.test.ts index 9d888c0fb8e..41e84632f65 100644 --- a/invokeai/frontend/webv2/src/workbench/canvasMigration.test.ts +++ b/invokeai/frontend/webv2/src/workbench/canvasMigration.test.ts @@ -74,6 +74,7 @@ describe('loadCanvasState', () => { { beginEndStepPct: [0, 1], controlMode: null, kind: 'control_lora', model: 'flux-control', weight: 0.75 }, { beginEndStepPct: [0.2, 0.9], controlMode: null, kind: 'z_image_control', model: 'z-control', weight: 0.7 }, { beginEndStepPct: [0, 0.8], controlMode: null, kind: 'anima_lllite', model: 'anima-sketch', weight: 1.2 }, + { beginEndStepPct: [0, 1], controlMode: null, kind: 'qwen_image_control', model: 'qwen-union', weight: 0.85 }, ] as const; const layers = adapters.map((adapter, index) => ({ ...createControlLayer(`Control ${index}`, `control-${index}`), @@ -139,6 +140,29 @@ describe('loadCanvasState', () => { }); }); + it('repairs a persisted Qwen-Image control weight below the node floor with the kind default', () => { + const loaded = load( + withNodes( + [ + { + ...createControlLayer('Q Control', 'q-control'), + adapter: { kind: 'qwen_image_control', model: 'qwen-union', weight: -0.5 }, + }, + ], + 'control' + ) + ); + const layer = loaded.document.stacks.control[0]; + + expect(layer?.type === 'control' ? layer.adapter : null).toEqual({ + beginEndStepPct: [0, 1], + controlMode: null, + kind: 'qwen_image_control', + model: 'qwen-union', + weight: 0.85, + }); + }); + it('round-trips a layer regenerate region and drops a malformed one without failing the layer', () => { const inpaint = { fill: { color: '#e07575', style: 'diagonal' }, diff --git a/invokeai/frontend/webv2/src/workbench/canvasMigration.ts b/invokeai/frontend/webv2/src/workbench/canvasMigration.ts index d6ee177e59f..04a27ff9ef4 100644 --- a/invokeai/frontend/webv2/src/workbench/canvasMigration.ts +++ b/invokeai/frontend/webv2/src/workbench/canvasMigration.ts @@ -12,6 +12,7 @@ import type { LayerStackKind, } from '@workbench/canvas-engine/api'; +import { getControlAdapterMinWeight } from '@features/generation/graph'; import { CANVAS_MAX_NODE_COUNT, CANVAS_MAX_NODE_DEPTH, LAYER_STACK_ORDER } from '@workbench/canvas-engine/api'; import { repairSelectedLayerId } from '@workbench/canvas-engine/document/selectionRepair'; import { z } from 'zod'; @@ -131,7 +132,14 @@ const zControlAdapter = z beginEndStepPct: z.tuple([zFiniteNumber, zFiniteNumber]), controlMode: z.enum(['balanced', 'more_prompt', 'more_control', 'unbalanced']).nullable(), // An unknown kind refuses the document: this build cannot apply it, and rewriting it would lose it on save. - kind: z.enum(['controlnet', 't2i_adapter', 'control_lora', 'z_image_control', 'anima_lllite']), + kind: z.enum([ + 'controlnet', + 't2i_adapter', + 'control_lora', + 'z_image_control', + 'anima_lllite', + 'qwen_image_control', + ]), model: z.string().nullable(), weight: zFiniteNumber, }) @@ -139,7 +147,7 @@ const zControlAdapter = z const [begin, end] = beginEndStepPct; return begin >= 0 && end <= 1 && begin < end; }) - .refine(({ kind, weight }) => weight >= (kind === 'z_image_control' ? 0 : -1) && weight <= 2); + .refine(({ kind, weight }) => weight >= getControlAdapterMinWeight(kind) && weight <= 2); const zMaskFill = z.object({ color: z.string(), style: z.enum(['solid', 'grid', 'crosshatch', 'diagonal', 'horizontal', 'vertical']), diff --git a/invokeai/frontend/webv2/src/workbench/controlAdapters.test.ts b/invokeai/frontend/webv2/src/workbench/controlAdapters.test.ts index f1f63a99663..3bbb9dfc91f 100644 --- a/invokeai/frontend/webv2/src/workbench/controlAdapters.test.ts +++ b/invokeai/frontend/webv2/src/workbench/controlAdapters.test.ts @@ -14,6 +14,7 @@ describe('normalizeControlAdapter', () => { ['control_lora', -1, [0, 1]], ['z_image_control', 0, [0.1, 0.9]], ['anima_lllite', -1, [0.1, 0.9]], + ['qwen_image_control', 0, [0.1, 0.9]], ] as const)('preserves valid %s numeric values', (kind, weight, beginEndStepPct) => { const adapter = { ...CONTROL_ADAPTER_DEFAULTS[kind], beginEndStepPct, weight }; expect(normalizeControlAdapter(adapter)).toEqual(adapter); @@ -27,11 +28,34 @@ describe('normalizeControlAdapter', () => { ['z_image_control', -0.01], ['z_image_control', 2.01], ['anima_lllite', 2.01], + ['qwen_image_control', -0.01], + ['qwen_image_control', 2.01], ] as const)('repairs invalid %s weight %s with its default', (kind, weight) => { const adapter = { ...CONTROL_ADAPTER_DEFAULTS[kind], weight }; expect(normalizeControlAdapter(adapter)).toMatchObject({ kind, weight: CONTROL_ADAPTER_DEFAULTS[kind].weight }); }); + it.each(['z_image_control', 'qwen_image_control'] as const)( + 'rebuilds a %s adapter from the contract fields', + (kind) => { + const persisted = { + beginEndStepPct: [0.1, 0.9], + controlMode: 'balanced', + extra: true, + kind, + model: 'm', + weight: 1.5, + }; + expect(normalizeControlAdapter(persisted)).toEqual({ + beginEndStepPct: [0.1, 0.9], + controlMode: null, + kind, + model: 'm', + weight: 1.5, + }); + } + ); + it.each([ [Number.NaN, 1], [0, Number.POSITIVE_INFINITY], @@ -49,10 +73,21 @@ describe('default control adapters', () => { it('starts each base on the one kind it accepts', () => { expect(getDefaultControlAdapterKind('anima')).toBe('anima_lllite'); expect(getDefaultControlAdapterKind('z-image')).toBe('z_image_control'); + expect(getDefaultControlAdapterKind('qwen-image')).toBe('qwen_image_control'); expect(getDefaultControlAdapterKind('sdxl')).toBe('controlnet'); expect(getDefaultControlAdapterKind(null)).toBe('controlnet'); }); + it('starts a Qwen-Image control at the union model card recommendation', () => { + expect(createDefaultControlAdapter('qwen-image', 'union')).toEqual({ + beginEndStepPct: [0, 1], + controlMode: null, + kind: 'qwen_image_control', + model: 'union', + weight: 0.85, + }); + }); + it('hands out a step range the caller may mutate without touching the defaults', () => { const adapter = createDefaultControlAdapter('anima'); adapter.beginEndStepPct[0] = 0.5; diff --git a/invokeai/frontend/webv2/src/workbench/controlAdapters.ts b/invokeai/frontend/webv2/src/workbench/controlAdapters.ts index 42eb62e61f0..8963492f277 100644 --- a/invokeai/frontend/webv2/src/workbench/controlAdapters.ts +++ b/invokeai/frontend/webv2/src/workbench/controlAdapters.ts @@ -1,6 +1,6 @@ import type { CanvasControlAdapterContract } from '@workbench/canvas-engine/api'; -import { areControlAdapterValuesValid } from '@features/generation/graph'; +import { areControlAdapterValuesValid, getControlAdapterMinWeight } from '@features/generation/graph'; export const CONTROL_ADAPTER_DEFAULTS: Readonly< Record @@ -26,6 +26,14 @@ export const CONTROL_ADAPTER_DEFAULTS: Readonly< model: null, weight: 0.75, }, + // The Fun-ControlNet-Union's recommended 0.70–0.95 context scale, centred. + qwen_image_control: { + beginEndStepPct: [0, 1], + controlMode: null, + kind: 'qwen_image_control', + model: null, + weight: 0.85, + }, t2i_adapter: { beginEndStepPct: [0, 1], controlMode: null, @@ -45,6 +53,7 @@ export const CONTROL_ADAPTER_DEFAULTS: Readonly< /** Kinds that exist for exactly one main-model base. Every other kind is offered wherever capabilities allow it. */ export const CONTROL_KIND_BASE: Readonly>> = { anima_lllite: 'anima', + qwen_image_control: 'qwen-image', z_image_control: 'z-image', }; @@ -77,7 +86,7 @@ export const normalizeControlAdapter = (value: unknown): unknown => { return value; } const defaults = CONTROL_ADAPTER_DEFAULTS[value.kind]; - const minWeight = value.kind === 'z_image_control' ? 0 : -1; + const minWeight = getControlAdapterMinWeight(value.kind); const weight = typeof value.weight === 'number' && Number.isFinite(value.weight) && value.weight >= minWeight && value.weight <= 2 ? value.weight @@ -86,13 +95,13 @@ export const normalizeControlAdapter = (value: unknown): unknown => { ? [value.beginEndStepPct[0], value.beginEndStepPct[1]] : [defaults.beginEndStepPct[0], defaults.beginEndStepPct[1]]; - if (value.kind !== 'z_image_control') { + if (value.kind !== 'z_image_control' && value.kind !== 'qwen_image_control') { return { ...defaults, ...value, beginEndStepPct, weight } satisfies CanvasControlAdapterContract; } return { beginEndStepPct, controlMode: null, - kind: 'z_image_control', + kind: value.kind, model: typeof value.model === 'string' ? value.model : null, weight, } satisfies CanvasControlAdapterContract; diff --git a/invokeai/frontend/webv2/src/workbench/controlLayerChecks.test.ts b/invokeai/frontend/webv2/src/workbench/controlLayerChecks.test.ts index 8d62b11da6d..67c3c49d2af 100644 --- a/invokeai/frontend/webv2/src/workbench/controlLayerChecks.test.ts +++ b/invokeai/frontend/webv2/src/workbench/controlLayerChecks.test.ts @@ -152,6 +152,25 @@ describe('getBlockingControlLayerIssues', () => { ]); }); + it('lets one Qwen-Image control through, and none on an Edit model', () => { + const qwenModels = [model('qwen-union', 'qwen-image', 'controlnet')]; + const layers = [ + controlLayer('first', { kind: 'qwen_image_control', model: 'qwen-union', weight: 0.85 }), + controlLayer('second', { kind: 'qwen_image_control', model: 'qwen-union', weight: 0.85 }), + ]; + const codes = (mainModel: { base: string; variant?: string }) => + getBlockingControlLayerIssues({ layers, mainModel, models: qwenModels }).map(({ code, layerId }) => [ + layerId, + code, + ]); + + expect(codes({ base: 'qwen-image' })).toEqual([['second', 'qwen_image_control_limit']]); + expect(codes({ base: 'qwen-image', variant: 'edit' })).toEqual([ + ['first', 'qwen_image_edit_control'], + ['second', 'qwen_image_edit_control'], + ]); + }); + it('reports issues in document order', () => { const issues = getBlockingControlLayerIssues({ layers: [controlLayer('top'), controlLayer('bottom')], @@ -167,11 +186,21 @@ describe('getControlLayerAttentionReason', () => { it('warns about a missing model even without content', () => { const layer = controlLayer('fresh', { source: { bitmap: null, type: 'paint' } }); - expect(getControlLayerAttentionReason(layer, 'sdxl', models)).toBe('missing_model'); + expect(getControlLayerAttentionReason(layer, sdxl, models)).toBe('missing_model'); }); it('returns null for a healthy layer and ignores per-kind limits', () => { - expect(getControlLayerAttentionReason(controlLayer('ok', { model: 'sdxl-control' }), 'sdxl', models)).toBeNull(); + expect(getControlLayerAttentionReason(controlLayer('ok', { model: 'sdxl-control' }), sdxl, models)).toBeNull(); + }); + + it('warns that an Edit model cannot run the Qwen-Image control', () => { + const qwenModels = [model('qwen-union', 'qwen-image', 'controlnet')]; + const layer = controlLayer('qwen', { kind: 'qwen_image_control', model: 'qwen-union', weight: 0.85 }); + + expect(getControlLayerAttentionReason(layer, { base: 'qwen-image' }, qwenModels)).toBeNull(); + expect(getControlLayerAttentionReason(layer, { base: 'qwen-image', variant: 'edit' }, qwenModels)).toBe( + 'qwen_image_edit_control' + ); }); }); diff --git a/invokeai/frontend/webv2/src/workbench/controlLayerChecks.ts b/invokeai/frontend/webv2/src/workbench/controlLayerChecks.ts index 55f4d669533..e6e0541ba32 100644 --- a/invokeai/frontend/webv2/src/workbench/controlLayerChecks.ts +++ b/invokeai/frontend/webv2/src/workbench/controlLayerChecks.ts @@ -88,7 +88,7 @@ export const getControlLayerReasonInSequence = (params: { /** Ambient warnings include empty layers but omit per-kind limits, which belong in the Invoke tooltip. */ export const getControlLayerAttentionReason = ( layer: CanvasControlLayerContract, - mainBase: string, + mainModel: MainModel, models: readonly ModelConfig[] ): ControlValidationReason | null => getControlValidationReason({ @@ -96,7 +96,9 @@ export const getControlLayerAttentionReason = ( beginEndStepPct: layer.adapter.beginEndStepPct, controlLoraIndex: 0, kind: layer.adapter.kind, - mainBase, + mainBase: mainModel.base, + mainVariant: mainModel.variant ?? undefined, + qwenImageControlIndex: 0, weight: layer.adapter.weight, zImageControlIndex: 0, }); diff --git a/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts b/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts index 9c8bf377fcd..e311bf6ed42 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts +++ b/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts @@ -1002,6 +1002,103 @@ describe('runCanvasInvocation', () => { expect(harness.notices()[0]?.message).toBe('second: z_image_control_limit'); }); + describe('Qwen Image ControlNet', () => { + const qwenImage = { + ...sd1Model, + base: 'qwen-image' as const, + format: 'diffusers' as const, + key: 'qwen-image', + name: 'Qwen Image', + }; + const union = { + base: 'qwen-image', + file_size: 1, + format: 'checkpoint', + hash: 'qwen-union-hash', + key: 'qwen-union', + name: 'Qwen Image ControlNet Union', + path: 'qwen-union', + source: 'qwen-union', + source_type: 'path' as const, + type: 'controlnet', + }; + const qwenLayer = (id: string, values: Partial = {}) => + controlLayer(id, { controlMode: null, kind: 'qwen_image_control', model: union.key, weight: 0.85, ...values }); + + it('prepares the control with the adapter values and the installed model', async () => { + const harness = makeHarness({ + document: docWithLayers([qwenLayer('q-layer', { beginEndStepPct: [0.1, 0.9], weight: 0.7 })]), + model: qwenImage, + models: [union], + }); + + await runCanvasInvocation(harness.deps); + + expect(harness.notices()).toHaveLength(0); + expect(harness.submittedGraphs()[0]?.graph.backendGraph?.nodes['qwen_image_control_q-layer']).toMatchObject({ + begin_step_percent: 0.1, + control_context_scale: 0.7, + control_model: { + base: 'qwen-image', + hash: 'qwen-union-hash', + key: 'qwen-union', + name: 'Qwen Image ControlNet Union', + type: 'controlnet', + }, + end_step_percent: 0.9, + type: 'qwen_image_control', + }); + expect(harness.surfaceIds).toEqual(['q-layer']); + }); + + it('hands the control the uploads the inpaint graph itself reads when the canvas inpaints', async () => { + const harness = makeHarness({ + document: docWithLayers([rasterLayer('base'), qwenLayer('q-layer'), inpaintMaskLayer('mask')]), + model: qwenImage, + models: [union], + }); + + await runCanvasInvocation(harness.deps); + + const submitted = harness.submittedGraphs(); + expect(submitted[0]?.graph.label).toBe('Qwen Image inpaint'); + const nodes = submitted[0]!.graph.backendGraph!.nodes; + expect(nodes['qwen_image_control_q-layer']?.inpaint_image).toEqual(nodes.create_gradient_mask?.image); + expect(nodes['qwen_image_control_mask_q-layer']).toMatchObject({ + image: nodes.create_gradient_mask?.mask, + max: 0, + min: 255, + type: 'img_lerp', + }); + }); + + it('blocks a second enabled nonempty control', async () => { + const harness = makeHarness({ + document: docWithLayers([qwenLayer('first'), qwenLayer('second')]), + model: qwenImage, + models: [union], + }); + + await runCanvasInvocation(harness.deps); + + expect(harness.submittedGraphs()).toHaveLength(0); + expect(harness.notices()[0]?.message).toBe('second: qwen_image_control_limit'); + }); + + it('blocks the control on a Qwen Image Edit model', async () => { + const harness = makeHarness({ + document: docWithLayers([qwenLayer('layer')]), + model: { ...qwenImage, variant: 'edit' }, + models: [union], + }); + + await runCanvasInvocation(harness.deps); + + expect(harness.submittedGraphs()).toHaveLength(0); + expect(harness.notices()[0]?.message).toBe('layer: qwen_image_edit_control'); + }); + }); + describe('Anima ControlNet-LLLite', () => { const anima = { ...sd1Model, base: 'anima' as const, key: 'anima', name: 'Anima' }; const installed = (key: string, base: string, type: string, extra: Record = {}) => ({ diff --git a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx index f92f7435123..e91b2716b1c 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx +++ b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx @@ -181,6 +181,25 @@ const offersKind = (kind: string) => host!.querySelector(`option[value="${kind}" const textOf = (role: 'alert' | 'status') => [...host!.querySelectorAll(`[role="${role}"]`)].map((element) => element.textContent).join(' '); const retryButton = () => [...host!.querySelectorAll('button')].find((button) => button.textContent === 'common.retry'); +/** The model Select's hidden native options, as the kind ones are read. */ +const offeredModels = () => + [...host!.querySelectorAll('select')] + .flatMap((select) => [...select.options].map((option) => option.value)) + .filter((value) => catalog.models.some((model) => model.key === value)); + +/** Renders `layers.at(-1)` as the selected layer of a document holding all of them, each with content. */ +const renderWith = async ( + mainModel: Record | null, + models: Record[], + ...layers: CanvasControlLayerContract[] +) => { + catalog.mainModel = mainModel as Record; + catalog.models = models; + commits.length = 0; + getArchitectureCapabilities.mockResolvedValueOnce(architectureCapabilitiesFixture); + await settle(ensureArchitectureCapabilitiesLoaded); + await render(layers.at(-1), engineWith(layers)); +}; afterEach(async () => { await act(() => root?.unmount()); @@ -298,11 +317,6 @@ describe('ControlLayerSettings on an Anima main model', () => { adapter: { ...base.adapter, ...values, kind: kind as CanvasControlLayerContract['adapter']['kind'] }, }; }; - /** The model Select's hidden native options, as the kind ones are read. */ - const offeredModels = () => - [...host!.querySelectorAll('select')] - .flatMap((select) => [...select.options].map((option) => option.value)) - .filter((value) => catalog.models.some((model) => model.key === value)); const button = (name: string) => [...host!.querySelectorAll('button')].find((b) => b.textContent === name); /** The adapter each commit wrote, read from the prepared edit's forward patch. */ const committedAdapters = () => @@ -313,19 +327,6 @@ describe('ControlLayerSettings on an Anima main model', () => { return match ? (JSON.parse(match[1]!) as Record) : null; }); - /** Renders `layers.at(-1)` as the selected layer of a document holding all of them, each with content. */ - const renderWith = async ( - mainModel: Record | null, - models: Record[], - ...layers: CanvasControlLayerContract[] - ) => { - catalog.mainModel = mainModel as Record; - catalog.models = models; - commits.length = 0; - getArchitectureCapabilities.mockResolvedValueOnce(architectureCapabilitiesFixture); - await settle(ensureArchitectureCapabilitiesLoaded); - await render(layers.at(-1), engineWith(layers)); - }; const ANIMA_MAIN = { base: 'anima', key: 'anima-main', name: 'Anima', type: 'main' }; const renderAnima = (...layers: CanvasControlLayerContract[]) => renderWith(ANIMA_MAIN, ANIMA_MODELS, ...layers); @@ -425,6 +426,46 @@ describe('ControlLayerSettings on an Anima main model', () => { }); }); +describe('ControlLayerSettings on a Qwen Image main model', () => { + const QWEN_MAIN = { base: 'qwen-image', key: 'qwen-main', name: 'Qwen Image 2512', type: 'main' }; + const QWEN_EDIT_MAIN = { ...QWEN_MAIN, key: 'qwen-edit', name: 'Qwen Image Edit 2511', variant: 'edit' }; + const QWEN_MODELS = [ + { base: 'qwen-image', key: 'qwen-union', name: 'Qwen Image ControlNet Union', type: 'controlnet' }, + { base: 'z-image', key: 'z-union', name: 'Z-Image ControlNet Union', type: 'controlnet' }, + ]; + /** A layer as the Layers panel creates it under a Qwen Image main model. */ + const qwenLayer = (id: string) => createControlLayer(id, id, 'qwen-image', 'qwen-union'); + + it('offers the Qwen Image ControlNet kind and its models, and accepts one without a warning', async () => { + await renderWith(QWEN_MAIN, QWEN_MODELS, qwenLayer('control-1')); + + expect(offersKind('qwen_image_control')).toBe(true); + expect(offersKind('controlnet')).toBe(false); + expect(offersKind('z_image_control')).toBe(false); + expect(offeredModels()).toEqual(['qwen-union']); + expect(host!.textContent).toContain('Qwen Image ControlNet Union'); + expect(textOf('alert')).toBe(''); + }); + + it('says the control cannot run on a Qwen Image Edit model', async () => { + await renderWith(QWEN_EDIT_MAIN, QWEN_MODELS, qwenLayer('control-1')); + + expect(textOf('alert')).toBe('widgets.layers.control.validation.qwen_image_edit_control'); + }); + + it('flags the second of two controls, but not the first', async () => { + const first = qwenLayer('first'); + const second = qwenLayer('second'); + await renderWith(QWEN_MAIN, QWEN_MODELS, first, second); + expect(textOf('alert')).toBe('widgets.layers.control.validation.qwen_image_control_limit'); + + await act(() => root?.unmount()); + host?.remove(); + await render(first, engineWith([first, second])); + expect(textOf('alert')).toBe(''); + }); +}); + describe('ControlLayerSettings weight', () => { // A full document layer (the panel reads its leaf), weighted 1 so a drag can move either way. const weighted = ((): CanvasControlLayerContract => { diff --git a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.tsx b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.tsx index a3f590d48c6..96a90a967e3 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.tsx +++ b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.tsx @@ -11,6 +11,7 @@ import type { CanvasStructuralEngine } from '@workbench/widgets/layers/layerOps' import { createListCollection, HStack, Stack, Switch, Text } from '@chakra-ui/react'; import { CONTROL_ADAPTER_KINDS, + getControlAdapterMinWeight, getControlModelUnusableReason, getSuggestedControlKind, isControlKindSupportedForBase, @@ -74,7 +75,7 @@ export const ControlLayerSettings = ({ engine, layer, onOperationStarted }: Cont const mainModel = useSelectedMainModel(); const base = mainModel?.base ?? null; const { adapter } = layer; - const weightInputMin = adapter.kind === 'z_image_control' ? 0 : CONTROL_WEIGHT_BOUNDS.inputMin; + const weightInputMin = getControlAdapterMinWeight(adapter.kind); // A previewed gesture records from where its preview started; any other change from the live adapter. const commitAdapter = useCallback( diff --git a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerWarningIcon.tsx b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerWarningIcon.tsx index b95fff467ea..cecc57a1b28 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerWarningIcon.tsx +++ b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerWarningIcon.tsx @@ -40,7 +40,7 @@ export const ControlLayerWarningIcon = ({ useCallback( () => layer.type === 'control' && contributing && mainModel - ? getControlLayerAttentionReason(layer, mainModel.base, models) + ? getControlLayerAttentionReason(layer, mainModel, models) : null, [contributing, layer, mainModel, models] ) diff --git a/invokeai/frontend/webv2/src/workbench/widgets/layers/controlModelOptions.test.ts b/invokeai/frontend/webv2/src/workbench/widgets/layers/controlModelOptions.test.ts index 51528e7caf0..e181f62f71a 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/layers/controlModelOptions.test.ts +++ b/invokeai/frontend/webv2/src/workbench/widgets/layers/controlModelOptions.test.ts @@ -27,6 +27,20 @@ describe('getCompatibleControlModels', () => { expect(getCompatibleControlModels(models, 'sd-1', 'z_image_control')).toEqual([]); }); + it('returns only Qwen-Image ControlNet models for qwen_image_control', () => { + const models = [ + model('qwen-union', 'qwen-image', 'controlnet'), + model('z-control', 'z-image', 'controlnet'), + model('qwen-lora', 'qwen-image', 'lora'), + ]; + + expect( + getCompatibleControlModels(models, 'qwen-image', 'qwen_image_control').map((candidate) => candidate.key) + ).toEqual(['qwen-union']); + expect(getCompatibleControlModels(models, 'z-image', 'qwen_image_control')).toEqual([]); + expect(getCompatibleControlModels(models, null, 'qwen_image_control')).toEqual([]); + }); + it('keeps existing adapter filtering unchanged', () => { const models = [model('sd-control', 'sd-1', 'controlnet'), model('flux-lora', 'flux', 'control_lora')]; expect(getCompatibleControlModels(models, 'sd-1', 'controlnet').map((candidate) => candidate.key)).toEqual([ @@ -88,6 +102,10 @@ describe('switchControlAdapterKind', () => { beginEndStepPct: [0, 0.75], weight: CONTROL_ADAPTER_DEFAULTS.z_image_control.weight, }); + expect(switchControlAdapterKind(negative, 'qwen_image_control', [], 'qwen-image')).toMatchObject({ + beginEndStepPct: [0, 0.75], + weight: CONTROL_ADAPTER_DEFAULTS.qwen_image_control.weight, + }); const unordered = { ...savedAsControlNet('sketch'), beginEndStepPct: [0.6, 0.2] as [number, number] }; expect(switchControlAdapterKind(unordered, 'anima_lllite', [sketch], 'anima')).toMatchObject({ beginEndStepPct: CONTROL_ADAPTER_DEFAULTS.anima_lllite.beginEndStepPct, @@ -135,4 +153,13 @@ describe('resolveDefaultControlModelForBase', () => { expect(resolveDefaultControlModelForBase(models, 'sd-1')).toBe('sd-control'); expect(resolveDefaultControlModelForBase(models, 'sd-2')).toBeNull(); }); + + it('starts a Qwen-Image control layer on the union ControlNet', () => { + const models = [ + model('qwen-canny', 'qwen-image', 'controlnet'), + { ...model('qwen-union', 'qwen-image', 'controlnet'), name: 'Qwen Image ControlNet Union' } as ModelConfig, + ]; + + expect(resolveDefaultControlModelForBase(models, 'qwen-image')).toBe('qwen-union'); + }); }); diff --git a/invokeai/frontend/webv2/src/workbench/widgets/layers/layerOps.test.ts b/invokeai/frontend/webv2/src/workbench/widgets/layers/layerOps.test.ts index 9dc55151f8b..bd6d288d61a 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/layers/layerOps.test.ts +++ b/invokeai/frontend/webv2/src/workbench/widgets/layers/layerOps.test.ts @@ -279,6 +279,13 @@ describe('createControlLayer', () => { model: null, weight: 0.75, }, + qwen_image_control: { + beginEndStepPct: [0, 1], + controlMode: null, + kind: 'qwen_image_control', + model: null, + weight: 0.85, + }, t2i_adapter: { beginEndStepPct: [0, 1], controlMode: null, kind: 't2i_adapter', model: null, weight: 1 }, z_image_control: { beginEndStepPct: [0, 1], diff --git a/tests/app/invocations/test_frontend_qwen_image_control_graphs.py b/tests/app/invocations/test_frontend_qwen_image_control_graphs.py new file mode 100644 index 00000000000..214bd29f208 --- /dev/null +++ b/tests/app/invocations/test_frontend_qwen_image_control_graphs.py @@ -0,0 +1,210 @@ +"""The Qwen Image ControlNet canvas graphs webv2 compiles are graphs this backend accepts. + +`qwenImageControlCanvasGraphs.json` is written by webv2's `compileCanvasGraph.test.ts` (regenerate with +`vitest -u`) from the real canvas compiler: a text-to-image submission with one control layer, an inpainting +submission where that layer also hands the control the canvas composite and the inverted canvas mask, and an +outpainting submission where it hands over the infilled image and the combined mask through edges. This module +checks more than names: pydantic validates every node against its invocation (bounds such as +`qwen_image_control.control_context_scale` in [0, 2] included), `Graph.validate_self` checks every edge type into +`qwen_image_denoise.control` and `.vae`, the control node's own `invoke` runs on the fields it would receive, and +`core_metadata` is serialised the way the gallery persists it. No model is loaded. +""" + +import json +from pathlib import Path +from typing import Any + +import pytest + +from invokeai.app.invocations.fields import ImageField +from invokeai.app.invocations.image import ImageLerpInvocation +from invokeai.app.invocations.metadata import CoreMetadataInvocation +from invokeai.app.invocations.qwen_image.qwen_image_control import QwenImageControlField, QwenImageControlInvocation +from invokeai.app.invocations.qwen_image.qwen_image_denoise import QwenImageDenoiseInvocation +from invokeai.app.invocations.sd.create_gradient_mask import CreateGradientMaskInvocation +from invokeai.app.services.shared.graph import Graph + +FIXTURE_PATH = ( + Path(__file__).parents[3] + / "invokeai" + / "frontend" + / "webv2" + / "src" + / "features" + / "generation" + / "core" + / "__snapshots__" + / "qwenImageControlCanvasGraphs.json" +) + +GRAPHS: dict[str, Any] = { + name: graph for name, graph in json.loads(FIXTURE_PATH.read_text(encoding="utf-8")).items() if name != "_comment" +} + + +@pytest.fixture(params=sorted(GRAPHS), ids=str) +def graph(request: pytest.FixtureRequest) -> Graph: + graph = Graph.model_validate(GRAPHS[request.param]) + graph.validate_self() + return graph + + +def _control_node(graph: Graph) -> QwenImageControlInvocation: + nodes = [node for node in graph.nodes.values() if isinstance(node, QwenImageControlInvocation)] + assert len(nodes) == 1 + return nodes[0] + + +def _denoise_node(graph: Graph) -> QwenImageDenoiseInvocation: + nodes = [node for node in graph.nodes.values() if isinstance(node, QwenImageDenoiseInvocation)] + assert len(nodes) == 1 + return nodes[0] + + +def _inputs(graph: Graph, node_id: str) -> dict[str, Any]: + """A node's edge-fed inputs, by destination field.""" + return {e.destination.field: e.source for e in graph.edges if e.destination.node_id == node_id} + + +def _control_field(graph: Graph, node: QwenImageControlInvocation) -> QwenImageControlField: + """The field the node would emit. `invoke` only repackages the node's own fields, so an image that an edge + supplies at run time stands in as the image its source node would produce.""" + runtime = node.model_copy( + update={ + field: ImageField(image_name=f"{node.id}.{field}") + for field in _inputs(graph, node.id) + if field in {"image", "inpaint_image", "inpaint_mask"} + } + ) + return runtime.invoke(None).control # type: ignore[arg-type] + + +def test_the_fixtures_cover_every_canvas_mode_with_one_control_layer() -> None: + assert sorted(GRAPHS) == ["inpaint_control_layer", "outpaint_control_layer", "txt2img_control_layer"] + for name, raw in GRAPHS.items(): + types = [node["type"] for node in raw["nodes"].values()] + assert types.count("qwen_image_control") == 1, name + assert types.count("qwen_image_denoise") == 1, name + + +@pytest.mark.parametrize("name", sorted(GRAPHS)) +def test_every_field_the_frontend_writes_is_one_the_invocation_declares(name: str) -> None: + """Pydantic ignores an unknown key, so a misnamed field (`weight` for `control_context_scale`) would validate + and run at its default. Values must also survive validation unchanged rather than being coerced.""" + graph = Graph.model_validate(GRAPHS[name]) + for node_id, raw in GRAPHS[name]["nodes"].items(): + node = graph.nodes[node_id] + if type(node).model_config.get("extra") == "allow": + # `core_metadata` records whatever the graph gives it, feature fields included, and persists the extras. + continue + unknown = set(raw) - set(type(node).model_fields) + assert unknown == set(), f"{raw['type']} has no field(s) {sorted(unknown)}" + if isinstance(node, QwenImageControlInvocation): + written = { + field: raw[field] for field in ("control_context_scale", "begin_step_percent", "end_step_percent") + } + assert {field: getattr(node, field) for field in written} == written + + +def test_the_control_reaches_the_denoise_directly_beside_the_vae_it_needs(graph: Graph) -> None: + """`qwen_image_denoise.control` is one field, not a collection, and the denoise refuses a control unless the + VAE that encodes its images is connected too.""" + control = _control_node(graph) + denoise = _denoise_node(graph) + inputs = _inputs(graph, denoise.id) + + assert (inputs["control"].node_id, inputs["control"].field) == (control.id, "control") + assert graph.nodes[inputs["vae"].node_id].get_type() == "qwen_image_model_loader" + assert inputs["vae"].field == "vae" + assert not any(node.get_type() == "collect" for node in graph.nodes.values()) + assert control.control_model.base.value == "qwen-image" + assert control.control_model.type.value == "controlnet" + assert control.control_context_scale == 0.85 + assert (control.begin_step_percent, control.end_step_percent) == (0.0, 1.0) + + +def test_text_to_image_sends_the_control_image_alone() -> None: + graph = Graph.model_validate(GRAPHS["txt2img_control_layer"]) + control = _control_node(graph) + + assert control.image is not None and control.image.image_name == "q-control.png" + assert control.inpaint_image is None and control.inpaint_mask is None + assert _inputs(graph, control.id) == {} + assert not any(isinstance(node, ImageLerpInvocation) for node in graph.nodes.values()) + field = _control_field(graph, control) + assert field.image_name == "q-control.png" + assert field.inpaint_image_name is None and field.inpaint_mask_name is None + + +def test_inpainting_adds_the_composite_and_the_inverted_uploaded_mask() -> None: + """Without Scale Before Processing the canvas uploads are read as fixed image fields, not through resize nodes. + The canvas mask is white = keep; the control regenerates white, so an `img_lerp` 255 -> 0 feeds its mask.""" + graph = Graph.model_validate(GRAPHS["inpaint_control_layer"]) + graph.validate_self() + control = _control_node(graph) + + assert control.image is not None and control.image.image_name == "q-control.png" + assert control.inpaint_image is not None and control.inpaint_image.image_name == "canvas-composite.png" + inputs = _inputs(graph, control.id) + assert set(inputs) == {"inpaint_mask"} + invert = graph.nodes[inputs["inpaint_mask"].node_id] + assert isinstance(invert, ImageLerpInvocation) + assert (invert.min, invert.max) == (255, 0) + assert invert.image.image_name == "canvas-mask.png" + assert inputs["inpaint_mask"].field == "image" + assert _inputs(graph, invert.id) == {} + # The denoise mask is the uploaded canvas mask as is; only the control gets the inverted copy. + gradient_mask = graph.nodes[_inputs(graph, _denoise_node(graph).id)["denoise_mask"].node_id] + assert isinstance(gradient_mask, CreateGradientMaskInvocation) + assert gradient_mask.mask.image_name == "canvas-mask.png" + field = _control_field(graph, control) + assert (field.image_name, field.inpaint_image_name) == ("q-control.png", "canvas-composite.png") + assert field.inpaint_mask_name == f"{control.id}.inpaint_mask" + + +def test_outpainting_adds_the_infilled_image_and_the_inverted_combined_mask() -> None: + graph = Graph.model_validate(GRAPHS["outpaint_control_layer"]) + graph.validate_self() + control = _control_node(graph) + + inputs = _inputs(graph, control.id) + assert set(inputs) == {"inpaint_image", "inpaint_mask"} + assert graph.nodes[inputs["inpaint_image"].node_id].get_type() == "infill_lama" + assert inputs["inpaint_image"].field == "image" + invert = graph.nodes[inputs["inpaint_mask"].node_id] + assert isinstance(invert, ImageLerpInvocation) + assert (invert.min, invert.max) == (255, 0) + assert inputs["inpaint_mask"].field == "image" + assert graph.nodes[_inputs(graph, invert.id)["image"].node_id].get_type() == "mask_combine" + # The control reads the same infilled image the encode the denoise starts from reads. + assert _inputs(graph, "canvas_i2l")["image"].node_id == inputs["inpaint_image"].node_id + field = _control_field(graph, control) + assert field.image_name == "q-control.png" + assert field.inpaint_image_name is not None and field.inpaint_mask_name is not None + + +def test_the_control_node_refuses_the_half_pair_the_frontend_never_sends() -> None: + """The frontend sends the inpaint image and mask together or not at all; pin the node constraint it mirrors.""" + graph = Graph.model_validate(GRAPHS["inpaint_control_layer"]) + control = _control_node(graph) + half = control.model_copy(update={"inpaint_mask": None}) + + with pytest.raises(ValueError, match="go together"): + half.invoke(None) # type: ignore[arg-type] + + +@pytest.mark.parametrize( + ("name", "mode"), + [ + ("txt2img_control_layer", "qwen_image_txt2img"), + ("inpaint_control_layer", "qwen_image_inpaint"), + ("outpaint_control_layer", "qwen_image_outpaint"), + ], +) +def test_persisted_metadata_records_the_canvas_mode(name: str, mode: str) -> None: + graph = Graph.model_validate(GRAPHS[name]) + metadata = next(node for node in graph.nodes.values() if isinstance(node, CoreMetadataInvocation)) + + persisted = metadata.invoke(None).metadata.root # type: ignore[arg-type] + + assert persisted["generation_mode"] == mode diff --git a/tests/app/invocations/test_qwen_image_control.py b/tests/app/invocations/test_qwen_image_control.py new file mode 100644 index 00000000000..d711745d87c --- /dev/null +++ b/tests/app/invocations/test_qwen_image_control.py @@ -0,0 +1,504 @@ +"""The Qwen Image ControlNet node, and what the denoise does with its field: refuses the pairings the branch was not +trained for, reserves the hints and the score matrices beside the activations, locks the branch with the same +reservation inside the exit stack, gates it per step, and builds the packed control context from the field's images +the way it packs its latents. + +The denoise runs its transformer in bfloat16, which the CPU test fleet cannot matmul, so every run here stops at the +transformer's lock or at the LoRA patcher, or runs the loop with the transformer's forward stood in. The forward with +the hooks is covered in `tests/backend/fun_controlnet`. +""" + +from contextlib import contextmanager, nullcontext +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest +import torch +from diffusers.models.autoencoders.autoencoder_kl_qwenimage import AutoencoderKLQwenImage +from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformer2DModel +from PIL import Image +from pydantic import ValidationError + +from invokeai.app.invocations.fields import ImageField +from invokeai.app.invocations.model import ModelIdentifierField, VAEField +from invokeai.app.invocations.qwen_image import qwen_image_denoise +from invokeai.app.invocations.qwen_image.qwen_image_control import QwenImageControlField, QwenImageControlInvocation +from invokeai.app.invocations.qwen_image.qwen_image_denoise import QwenImageDenoiseInvocation +from invokeai.app.invocations.vae.qwen_image_image_to_latents import QwenImageImageToLatentsInvocation +from invokeai.backend.fun_controlnet.hooks import FunControlHooks +from invokeai.backend.fun_controlnet.qwen_image import QwenImageFunControlBranch +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType +from invokeai.backend.patches.layer_patcher import LayerPatcher +from invokeai.backend.stable_diffusion.diffusers_pipeline import image_resized_to_grid_as_tensor +from invokeai.backend.stable_diffusion.diffusion.conditioning_data import ( + ConditioningFieldData, + QwenImageConditioningInfo, +) +from invokeai.backend.util import attention +from invokeai.backend.util.attention import SDPA_MATH_BYTES_PER_SCORE_ELEMENT +from invokeai.backend.util.devices import TorchDevice + +SIDE = 64 # an 8x8 latent: 16 image tokens +LATENT_SIDE = SIDE // 8 +TEXT_TOKENS = 4 +CONTROL_LAYERS = (0, 2) +HIDDEN = 16 + + +class _Stop(Exception): + """Raised where the node has made the decision a test looks at.""" + + +def _model(type_: ModelType) -> ModelIdentifierField: + return ModelIdentifierField( + key=f"{type_.value}", hash="hash", name=type_.value, base=BaseModelType.QwenImage, type=type_ + ) + + +# --- the node --- + + +def test_the_node_hands_its_images_and_settings_to_the_field() -> None: + node = QwenImageControlInvocation( + id="control", + control_model=_model(ModelType.ControlNet), + image=ImageField(image_name="canny"), + inpaint_image=ImageField(image_name="photo"), + inpaint_mask=ImageField(image_name="mask"), + control_context_scale=0.7, + begin_step_percent=0.1, + end_step_percent=0.9, + tiled=True, + tile_size=512, + ) + + assert node.invoke(MagicMock()).control == QwenImageControlField( + image_name="canny", + inpaint_image_name="photo", + inpaint_mask_name="mask", + control_model=_model(ModelType.ControlNet), + control_context_scale=0.7, + begin_step_percent=0.1, + end_step_percent=0.9, + tiled=True, + tile_size=512, + ) + + +@pytest.mark.parametrize( + "images", + [ + {"image": ImageField(image_name="canny")}, + {"inpaint_image": ImageField(image_name="photo"), "inpaint_mask": ImageField(image_name="mask")}, + ], + ids=["control-alone", "inpaint-alone"], +) +def test_a_control_image_alone_or_an_inpaint_pair_alone_is_enough(images) -> None: + node = QwenImageControlInvocation(id="control", control_model=_model(ModelType.ControlNet), **images) + field = node.invoke(MagicMock()).control + assert (field.image_name, field.inpaint_image_name, field.inpaint_mask_name) == ( + "canny" if "image" in images else None, + "photo" if "inpaint_image" in images else None, + "mask" if "inpaint_mask" in images else None, + ) + + +@pytest.mark.parametrize( + ("images", "message"), + [ + ({}, "control image"), + ({"inpaint_mask": ImageField(image_name="mask")}, "go together"), + ({"inpaint_image": ImageField(image_name="photo")}, "go together"), + ], + ids=["nothing", "mask-alone", "image-alone"], +) +def test_the_node_refuses_to_run_without_a_complete_input(images, message) -> None: + node = QwenImageControlInvocation(id="control", control_model=_model(ModelType.ControlNet), **images) + with pytest.raises(ValueError, match=message): + node.invoke(MagicMock()) + + +def test_a_begin_after_the_end_is_refused_when_the_node_is_built() -> None: + with pytest.raises(ValidationError, match="Begin step percent"): + QwenImageControlInvocation( + id="control", control_model=_model(ModelType.ControlNet), begin_step_percent=0.8, end_step_percent=0.2 + ) + + +# --- the denoise --- + + +@pytest.fixture(autouse=True) +def cpu(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(TorchDevice, "choose_torch_device", lambda: torch.device("cpu")) + + +@pytest.fixture(autouse=True) +def fused_sdpa(monkeypatch: pytest.MonkeyPatch) -> None: + """Answer the dispatch questions `sdpa_score_matrix_bytes` asks, so no test depends on the torch build of the + machine it runs on: fused, unless a test says otherwise.""" + monkeypatch.setattr(attention, "_diffusers_attention_dispatch", lambda: attention._DISPATCH_TORCH) + monkeypatch.setattr(attention, "rocm_sdpa_uses_math_kernel", lambda *_args: False) + monkeypatch.setattr(attention, "_torch_sdpa_materializes_score_matrix", lambda *_args: False) + + +def _tiny_transformer(zero_cond_t: bool = False) -> QwenImageTransformer2DModel: + return QwenImageTransformer2DModel( + patch_size=2, + in_channels=64, + out_channels=16, + num_layers=4, + attention_head_dim=8, + num_attention_heads=2, + joint_attention_dim=8, + axes_dims_rope=(2, 4, 2), + zero_cond_t=zero_cond_t, + ).eval() + + +def _tiny_branch() -> QwenImageFunControlBranch: + return QwenImageFunControlBranch( + hidden_size=HIDDEN, num_attention_heads=2, attention_head_dim=8, control_layers=CONTROL_LAYERS + ).eval() + + +def _tiny_vae() -> AutoencoderKLQwenImage: + # The smallest configuration that keeps the real 8x spatial compression and 16 latent channels. + return AutoencoderKLQwenImage( + base_dim=4, + z_dim=16, + dim_mult=[1, 1, 1, 1], + num_res_blocks=1, + attn_scales=[], + temperal_downsample=[False, True, True], + ).eval() + + +def _loaded(model, lock) -> MagicMock: + """A `LoadedModel` stand-in: `model` unlocked, `model_on_device` as `lock` says (a context or a raise).""" + info = MagicMock() + info.model = model + info.compute_device = torch.device("cpu") + info.model_on_device = MagicMock(side_effect=lock) + return info + + +def _yielding(model): + return lambda working_mem_bytes=None: nullcontext((None, model)) + + +def _stopping(working_mem_bytes=None): + raise _Stop + + +def _control_field(**overrides) -> QwenImageControlField: + field = { + "image_name": "canny", + "inpaint_image_name": "photo", + "inpaint_mask_name": "mask", + "control_model": _model(ModelType.ControlNet), + } + field.update(overrides) + return QwenImageControlField(**field) + + +def _denoise(**overrides) -> QwenImageDenoiseInvocation: + fields = { + "latents": None, + "reference_latents": None, + "denoise_mask": None, + "denoising_start": 0.0, + "denoising_end": 1.0, + "transformer": SimpleNamespace(transformer=_model(ModelType.Main), loras=[]), + "positive_conditioning": SimpleNamespace(conditioning_name="pos"), + "negative_conditioning": SimpleNamespace(conditioning_name="neg"), + "cfg_scale": 4.0, + "width": SIDE, + "height": SIDE, + "steps": 2, + "seed": 0, + "shift": None, + "control": _control_field(), + "vae": VAEField(vae=_model(ModelType.VAE)), + } + fields.update(overrides) + return QwenImageDenoiseInvocation.model_construct(**fields) + + +def _control_image() -> Image.Image: + return Image.linear_gradient("L").resize((SIDE // 2, SIDE // 2)).convert("RGB") + + +def _inpaint_image() -> Image.Image: + return Image.linear_gradient("L").rotate(90).resize((SIDE, SIDE)).convert("RGB") + + +def _inpaint_mask() -> Image.Image: + """White (regenerate) in the top-left quarter.""" + mask = Image.new("L", (SIDE, SIDE), 0) + mask.paste(255, (0, 0, SIDE // 2, SIDE // 2)) + return mask + + +def _context(tmp_path, transformer_info=None, control_info=None, vae_info=None, masked_prompt=False) -> MagicMock: + infos = {ModelType.Main: transformer_info, ModelType.ControlNet: control_info, ModelType.VAE: vae_info} + context = MagicMock() + context.models.load.side_effect = lambda identifier: infos[identifier.type] + context.models.get_config.return_value = SimpleNamespace( + base=BaseModelType.QwenImage, type=ModelType.Main, format=ModelFormat.Checkpoint + ) + # No `scheduler/` beside it: the node falls back to the Qwen-Image schedule defaults. + context.models.get_absolute_path.return_value = tmp_path / "qwen_image.safetensors" + prompt_mask = torch.ones(1, TEXT_TOKENS, dtype=torch.bool) if masked_prompt else None + context.conditioning.load.side_effect = lambda name: ConditioningFieldData( + conditionings=[ + QwenImageConditioningInfo(prompt_embeds=torch.zeros(1, TEXT_TOKENS, 8), prompt_embeds_mask=prompt_mask) + ] + ) + images = {"canny": _control_image(), "photo": _inpaint_image(), "mask": _inpaint_mask()} + context.images.get_pil.side_effect = lambda name: images[name] + context.config.get.return_value.force_tiled_decode = False + return context + + +def _hook_count(transformer) -> int: + return sum(len(block._forward_hooks) + len(block._forward_pre_hooks) for block in transformer.transformer_blocks) + + +@pytest.mark.parametrize( + ("overrides", "message"), + [ + ({"vae": None}, "needs the VAE"), + ({"reference_latents": SimpleNamespace(latents_name="reference")}, "reference latents"), + ], + ids=["no-vae", "reference-latents"], +) +def test_control_is_refused_without_its_vae_or_beside_reference_latents(tmp_path, overrides, message) -> None: + context = _context(tmp_path, transformer_info=_loaded(_tiny_transformer(), _stopping)) + + with pytest.raises(ValueError, match=message): + _denoise(**overrides)._run_diffusion(context) + + # Only the transformer was loaded: nothing else is fetched for a run that cannot happen. + assert context.models.load.call_count == 1 + + +def test_control_is_refused_on_an_edit_transformer(tmp_path) -> None: + context = _context(tmp_path, transformer_info=_loaded(_tiny_transformer(zero_cond_t=True), _stopping)) + + with pytest.raises(ValueError, match="Edit transformer"): + _denoise()._run_diffusion(context) + + assert context.models.load.call_count == 1 + + +def test_without_control_the_lock_reserves_the_activations_alone(tmp_path) -> None: + transformer_info = _loaded(_tiny_transformer(), _stopping) + context = _context(tmp_path, transformer_info=transformer_info) + + with pytest.raises(_Stop): + _denoise(control=None, vae=None)._run_diffusion(context) + + expected = QwenImageDenoiseInvocation._estimate_working_memory( + image_seq_len=16, text_seq_len=TEXT_TOKENS, element_size=torch.bfloat16.itemsize + ) + assert transformer_info.model_on_device.call_args.kwargs["working_mem_bytes"] == expected + + +def test_with_control_the_lock_reserves_the_hints_too_and_the_images_are_encoded_first(tmp_path) -> None: + transformer_info = _loaded(_tiny_transformer(), _stopping) + branch, vae = _tiny_branch(), _tiny_vae() + vae_info = _loaded(vae, _yielding(vae)) + context = _context(tmp_path, transformer_info, _loaded(branch, _yielding(branch)), vae_info) + + with pytest.raises(_Stop): + _denoise()._run_diffusion(context) + + expected = QwenImageDenoiseInvocation._estimate_working_memory( + image_seq_len=16, + text_seq_len=TEXT_TOKENS, + element_size=torch.bfloat16.itemsize, + num_control_blocks=len(CONTROL_LAYERS), + control_hidden_size=HIDDEN, + ) + assert transformer_info.model_on_device.call_args.kwargs["working_mem_bytes"] == expected + # The control image and the masked inpaint image went through the VAE before the transformer was locked. + assert vae_info.model_on_device.call_count == 2 + + +def test_a_build_that_materializes_the_scores_reserves_them_too(tmp_path, monkeypatch: pytest.MonkeyPatch) -> None: + """ROCm on Windows and MPS have no fused kernel for the joint sequence; the 1 GiB base does not cover 24 heads of + 4608^2 scores, so the probe's answer has to reach the reservation.""" + monkeypatch.setattr(attention, "_torch_sdpa_materializes_score_matrix", lambda *_args: True) + transformer_info = _loaded(_tiny_transformer(), _stopping) + context = _context(tmp_path, transformer_info=transformer_info) + + with pytest.raises(_Stop): + _denoise(control=None, vae=None)._run_diffusion(context) + + activations = QwenImageDenoiseInvocation._estimate_working_memory( + image_seq_len=16, text_seq_len=TEXT_TOKENS, element_size=torch.bfloat16.itemsize + ) + # The tiny transformer's two heads over the 16 + 4 token joint sequence. + scores = 2 * (16 + TEXT_TOKENS) ** 2 * SDPA_MATH_BYTES_PER_SCORE_ELEMENT + assert transformer_info.model_on_device.call_args.kwargs["working_mem_bytes"] == activations + scores + + +@pytest.mark.parametrize("masked_prompt", [False, True], ids=["no-mask", "mask"]) +def test_the_prompt_mask_reaches_the_attention_probe(tmp_path, monkeypatch: pytest.MonkeyPatch, masked_prompt) -> None: + """A mask narrows which fused kernels a build can use, so the probe is told whether the encoder emitted one.""" + asked_with: list[bool] = [] + monkeypatch.setattr( + attention, "_torch_sdpa_materializes_score_matrix", lambda *args: asked_with.append(args[-1]) or False + ) + context = _context(tmp_path, transformer_info=_loaded(_tiny_transformer(), _stopping), masked_prompt=masked_prompt) + + with pytest.raises(_Stop): + _denoise(control=None, vae=None)._run_diffusion(context) + + assert asked_with == [masked_prompt] + + +def test_the_branch_is_locked_with_the_same_reservation_and_hooked_inside_the_exit_stack( + tmp_path, monkeypatch: pytest.MonkeyPatch +) -> None: + transformer, branch, vae = _tiny_transformer(), _tiny_branch(), _tiny_vae() + transformer_info = _loaded(transformer, _yielding(transformer)) + control_info = _loaded(branch, _yielding(branch)) + context = _context(tmp_path, transformer_info, control_info, _loaded(vae, _yielding(vae))) + hooks_at_patching: list[int] = [] + + def stop(**_kwargs): + hooks_at_patching.append(_hook_count(transformer)) + raise _Stop + + monkeypatch.setattr(LayerPatcher, "apply_smart_model_patches", stop) + + with pytest.raises(_Stop): + _denoise()._run_diffusion(context) + + reserved = transformer_info.model_on_device.call_args.kwargs["working_mem_bytes"] + assert control_info.model_on_device.call_args.kwargs["working_mem_bytes"] == reserved + assert hooks_at_patching == [1 + len(CONTROL_LAYERS)] + assert _hook_count(transformer) == 0 + + +class _GateRecordingTransformer(QwenImageTransformer2DModel): + """The real class, so the node's isinstance checks hold and the real hooks land on its blocks, with the forward + replaced: no bfloat16 matmul on the CPU, and a record of the control gate at every call.""" + + def __init__(self) -> None: + super().__init__( + patch_size=2, + in_channels=64, + out_channels=16, + num_layers=4, + attention_head_dim=8, + num_attention_heads=2, + joint_attention_dim=8, + axes_dims_rope=(2, 4, 2), + ) + self.hooks: FunControlHooks | None = None + self.gates: list[bool] = [] + + def forward(self, hidden_states: torch.Tensor, *_args, **_kwargs): + assert self.hooks is not None + self.gates.append(self.hooks.active) + return (torch.zeros(*hidden_states.shape[:2], 4 * self.out_channels, dtype=hidden_states.dtype),) + + +@pytest.mark.parametrize( + ("begin", "end", "expected_gates"), + [ + (0.5, 1.0, [False] * 4 + [True] * 4), + (0.0, 0.5, [True] * 6 + [False] * 2), + ], + ids=["second-half", "first-half"], +) +def test_the_gate_is_set_once_per_step_for_both_guidance_branches( + tmp_path, monkeypatch: pytest.MonkeyPatch, begin, end, expected_gates +) -> None: + """Four steps with CFG are eight forwards: the gate follows `step_index / total_steps` with both ends included, + is re-evaluated every step, and the positive and the negative forward of a step see the same one.""" + transformer, branch, vae = _GateRecordingTransformer(), _tiny_branch(), _tiny_vae() + install = qwen_image_denoise.install_fun_control + + @contextmanager + def capturing_install(*args, **kwargs): + with install(*args, **kwargs) as hooks: + transformer.hooks = hooks + yield hooks + + monkeypatch.setattr(qwen_image_denoise, "install_fun_control", capturing_install) + context = _context( + tmp_path, + _loaded(transformer, _yielding(transformer)), + _loaded(branch, _yielding(branch)), + _loaded(vae, _yielding(vae)), + ) + + _denoise(steps=4, control=_control_field(begin_step_percent=begin, end_step_percent=end))._run_diffusion(context) + + assert transformer.gates == expected_gates + + +@pytest.mark.parametrize( + ("tiled", "tile_size", "force_tiled_decode", "expected_tiled"), + [(False, 0, False, False), (True, 512, False, True), (False, 0, True, True)], + ids=["untiled", "field", "forced"], +) +def test_the_control_images_are_encoded_with_the_fields_tiling( + tmp_path, monkeypatch: pytest.MonkeyPatch, tiled, tile_size, force_tiled_decode, expected_tiled +) -> None: + vae = _tiny_vae() + context = _context(tmp_path, vae_info=_loaded(vae, _yielding(vae))) + context.config.get.return_value.force_tiled_decode = force_tiled_decode + encode = QwenImageImageToLatentsInvocation.vae_encode + encoded_with: list[tuple[bool, int]] = [] + + def recording(**kwargs): + encoded_with.append((kwargs["tiled"], kwargs["tile_size"])) + return encode(**kwargs) + + monkeypatch.setattr(QwenImageImageToLatentsInvocation, "vae_encode", staticmethod(recording)) + + _denoise(control=_control_field(tiled=tiled, tile_size=tile_size))._build_control_context( + context, LATENT_SIDE, LATENT_SIDE + ) + + # Once for the control image, once for the masked inpaint image, both with the field's tiling. + assert encoded_with == [(expected_tiled, tile_size)] * 2 + + +def _as_denoise_input(image: Image.Image, mode: str) -> torch.Tensor: + """What the node feeds the VAE: the image at generation size, pixels in [-1, 1], a mask in [0, 1].""" + resample = Image.Resampling.LANCZOS if mode == "RGB" else Image.Resampling.BILINEAR + resized = image.convert(mode).resize((SIDE, SIDE), resample) + return image_resized_to_grid_as_tensor(resized, normalize=mode == "RGB", multiple_of=16).unsqueeze(0) + + +def test_the_control_context_is_the_encoded_images_packed_like_the_latents(tmp_path) -> None: + vae = _tiny_vae() + vae_info = _loaded(vae, _yielding(vae)) + context = _context(tmp_path, vae_info=vae_info) + + packed = _denoise()._build_control_context(context, LATENT_SIDE, LATENT_SIDE) + + assert packed.shape == (1, (LATENT_SIDE // 2) ** 2, 33 * 4) + # Channel-major within a token: feature c * 4 + dy * 2 + dx of token (i, j) is channel c at (2i + dy, 2j + dx). + context_4d = QwenImageDenoiseInvocation._unpack_latents(packed, LATENT_SIDE, LATENT_SIDE) + assert context_4d.shape == (1, 33, LATENT_SIDE, LATENT_SIDE) + for channel, i, j, dy, dx in [(0, 0, 0, 0, 0), (16, 1, 2, 1, 0), (32, 3, 3, 1, 1), (7, 2, 1, 0, 1)]: + token = i * (LATENT_SIDE // 2) + j + assert packed[0, token, channel * 4 + dy * 2 + dx] == context_4d[0, channel, 2 * i + dy, 2 * j + dx] + + def encode(pixels: torch.Tensor) -> torch.Tensor: + return QwenImageImageToLatentsInvocation.vae_encode(vae_info, pixels).squeeze(2) + + assert torch.equal(context_4d[:, :16], encode(_as_denoise_input(_control_image(), "RGB"))) + expected_keep = torch.ones(LATENT_SIDE, LATENT_SIDE) + expected_keep[: LATENT_SIDE // 2, : LATENT_SIDE // 2] = 0.0 + assert torch.equal(context_4d[0, 16], expected_keep) + masked = _as_denoise_input(_inpaint_image(), "RGB") + masked[..., : SIDE // 2, : SIDE // 2] = 0.0 + assert torch.equal(context_4d[:, 17:], encode(masked)) diff --git a/tests/app/invocations/test_qwen_image_packed_models.py b/tests/app/invocations/test_qwen_image_packed_models.py index 73273ec1483..37e77671a01 100644 --- a/tests/app/invocations/test_qwen_image_packed_models.py +++ b/tests/app/invocations/test_qwen_image_packed_models.py @@ -1,8 +1,9 @@ """The Qwen-Image nodes have to treat a packed nvfp4 model like the other nodes treat one. -The denoise node reserves the per-forward dequantization transient of packed Linears and applies LoRA to them as -sidecars, which it used to decide from the format alone -- GGUF only -- so a `checkpoint` build holding packed Linears -would have been patched directly. The text encoder node reserves the same transient. +The denoise node reserves the per-forward dequantization transient of packed Linears on top of its activation +estimate and applies LoRA to them as sidecars, which it used to decide from the format alone -- GGUF only -- so a +`checkpoint` build holding packed Linears would have been patched directly. The text encoder node reserves the same +transient. """ from contextlib import contextmanager, nullcontext @@ -108,7 +109,9 @@ def stop(**kwargs): with pytest.raises(_Stop): _denoise_node()._run_diffusion(context) - assert loaded.model_on_device.call_args.kwargs["working_mem_bytes"] == transient + # 64x64 is 16 image tokens; the stubbed conditioning is 4 text tokens, in bf16. + activations = QwenImageDenoiseInvocation._estimate_working_memory(image_seq_len=16, text_seq_len=4, element_size=2) + assert loaded.model_on_device.call_args.kwargs["working_mem_bytes"] == activations + transient assert patching["force_sidecar_patching"] is sidecar diff --git a/tests/backend/architectures/test_features.py b/tests/backend/architectures/test_features.py index 5b8aa98956e..94970513b58 100644 --- a/tests/backend/architectures/test_features.py +++ b/tests/backend/architectures/test_features.py @@ -70,6 +70,7 @@ def test_the_sd_family_grid_is_the_vae_compression() -> None: ("control_lora", {"flux"}), ("z_image_control", {"z-image"}), ("anima_lllite", {"anima"}), + ("qwen_image_control", {"qwen-image"}), ], ) def test_control_kinds_match_the_frontend_policy(kind: ControlKind, expected: set[str]) -> None: diff --git a/tests/backend/fun_controlnet/conftest.py b/tests/backend/fun_controlnet/conftest.py new file mode 100644 index 00000000000..fa75d8e1c4c --- /dev/null +++ b/tests/backend/fun_controlnet/conftest.py @@ -0,0 +1,50 @@ +import pytest +import torch +from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformer2DModel + +from invokeai.backend.fun_controlnet.qwen_image import QwenImageFunControlBranch + +TINY_HIDDEN = 16 +TINY_HEADS = 2 +TINY_HEAD_DIM = 8 +TINY_LAYERS = 4 +TINY_TEXT_DIM = 24 +TINY_CONTROL_LAYERS = (0, 2) + + +@pytest.fixture +def tiny_qwen_image_transformer() -> QwenImageTransformer2DModel: + """The real Qwen-Image transformer at toy width (16, two heads of 8), four blocks, in float32 on the CPU. + + Every parameter is drawn from N(0, 0.1): the default init leaves the modulation gates near zero, which would hide + a hint a test is looking for. + """ + torch.manual_seed(0) + model = QwenImageTransformer2DModel( + patch_size=2, + in_channels=64, + out_channels=16, + num_layers=TINY_LAYERS, + attention_head_dim=TINY_HEAD_DIM, + num_attention_heads=TINY_HEADS, + joint_attention_dim=TINY_TEXT_DIM, + axes_dims_rope=(2, 4, 2), + ).eval() + for param in model.parameters(): + torch.nn.init.normal_(param, std=0.1) + return model + + +@pytest.fixture +def tiny_branch() -> QwenImageFunControlBranch: + """Two control blocks for the tiny transformer, their hints landing after base blocks 0 and 2.""" + torch.manual_seed(1) + branch = QwenImageFunControlBranch( + hidden_size=TINY_HIDDEN, + num_attention_heads=TINY_HEADS, + attention_head_dim=TINY_HEAD_DIM, + control_layers=TINY_CONTROL_LAYERS, + ).eval() + for param in branch.parameters(): + torch.nn.init.normal_(param, std=0.1) + return branch diff --git a/tests/backend/fun_controlnet/test_qwen_image_control_conditioning.py b/tests/backend/fun_controlnet/test_qwen_image_control_conditioning.py new file mode 100644 index 00000000000..139d54f29f4 --- /dev/null +++ b/tests/backend/fun_controlnet/test_qwen_image_control_conditioning.py @@ -0,0 +1,145 @@ +"""The Qwen-Image Fun control context: which channel carries what, and what the inpaint mask does to each. + +Expected values are built here from the recipe (VideoX-Fun `pipeline_qwenimage_control.py`), not read back from the +function: the keep mask is `1 - mask` nearest-sampled to latent size, and the masked image has every pixel the mask +marks (>= 0.5) zeroed before it is encoded. +""" + +import pytest +import torch +import torch.nn.functional as F + +from invokeai.backend.fun_controlnet.conditioning import build_qwen_image_control_context + +SIDE = 32 +LATENT_SIDE = SIDE // 8 +LATENT_CHANNELS = 16 + + +class _Encoder: + """Stands in for the VAE: an 8x average pool spread over 16 channels, deterministic and shape-faithful. Records + what it was asked to encode, which is where the masked image is checked.""" + + def __init__(self) -> None: + self.inputs: list[torch.Tensor] = [] + + def __call__(self, pixels: torch.Tensor) -> torch.Tensor: + self.inputs.append(pixels.clone()) + pooled = F.avg_pool2d(pixels, 8) + return torch.cat([pooled] * 5 + [pooled[:, :1]], dim=1) + + +def _image(seed: int) -> torch.Tensor: + return torch.rand(1, 3, SIDE, SIDE, generator=torch.Generator().manual_seed(seed)) * 2 - 1 + + +def _quadrant_mask() -> torch.Tensor: + """White (regenerate) in the top-left quarter, black (keep) elsewhere.""" + mask = torch.zeros(1, 1, SIDE, SIDE) + mask[..., : SIDE // 2, : SIDE // 2] = 1.0 + return mask + + +def test_pure_control_fills_the_control_channels_and_leaves_the_inpaint_channels_at_zero() -> None: + encode = _Encoder() + control_image = _image(0) + + context = build_qwen_image_control_context(encode=encode, control_image=control_image) + + assert context.shape == (1, 2 * LATENT_CHANNELS + 1, LATENT_SIDE, LATENT_SIDE) + assert torch.equal(context[:, :LATENT_CHANNELS], _Encoder()(control_image)) + assert torch.equal(context[:, LATENT_CHANNELS:], torch.zeros(1, LATENT_CHANNELS + 1, LATENT_SIDE, LATENT_SIDE)) + assert len(encode.inputs) == 1 and torch.equal(encode.inputs[0], control_image) + + +def test_pure_inpaint_carries_the_keep_mask_and_the_masked_image_and_no_control() -> None: + encode = _Encoder() + inpaint_image = _image(1) + mask = _quadrant_mask() + + context = build_qwen_image_control_context(encode=encode, inpaint_image=inpaint_image, inpaint_mask=mask) + + assert torch.equal(context[:, :LATENT_CHANNELS], torch.zeros(1, LATENT_CHANNELS, LATENT_SIDE, LATENT_SIDE)) + expected_keep = torch.ones(1, 1, LATENT_SIDE, LATENT_SIDE) + expected_keep[..., : LATENT_SIDE // 2, : LATENT_SIDE // 2] = 0.0 + assert torch.equal(context[:, LATENT_CHANNELS : LATENT_CHANNELS + 1], expected_keep) + # The encoder saw the inpaint image with the regenerated quarter zeroed and nothing else changed. + (encoded,) = encode.inputs + assert torch.equal(encoded[..., : SIDE // 2, : SIDE // 2], torch.zeros(1, 3, SIDE // 2, SIDE // 2)) + assert torch.equal(encoded[..., SIDE // 2 :, :], inpaint_image[..., SIDE // 2 :, :]) + assert torch.equal(encoded[..., :, SIDE // 2 :], inpaint_image[..., :, SIDE // 2 :]) + assert torch.equal(context[:, LATENT_CHANNELS + 1 :], _Encoder()(encoded)) + + +def test_control_and_inpaint_together_fill_both_halves() -> None: + encode = _Encoder() + control_image, inpaint_image = _image(2), _image(3) + + context = build_qwen_image_control_context( + encode=encode, control_image=control_image, inpaint_image=inpaint_image, inpaint_mask=_quadrant_mask() + ) + + assert torch.equal(context[:, :LATENT_CHANNELS], _Encoder()(control_image)) + assert context[:, LATENT_CHANNELS].sum() == LATENT_SIDE * LATENT_SIDE * 3 / 4 + assert torch.equal(context[:, LATENT_CHANNELS + 1 :], _Encoder()(encode.inputs[1])) + + +def test_a_soft_mask_is_thresholded_before_it_becomes_the_keep_channel() -> None: + """A blurred mask (0.5, 0.3, 0.9 bands) must give a 0/1 keep channel that agrees with the zeroed pixels: exactly + the pixels at or above 0.5 are regenerated and read 0 in the channel, the rest are kept and read 1.""" + encode = _Encoder() + inpaint_image = torch.ones(1, 3, SIDE, SIDE) + mask = torch.zeros(1, 1, SIDE, SIDE) + mask[..., :8, :] = 0.5 + mask[..., 8:16, :] = 0.3 + mask[..., 16:24, :] = 0.9 + + context = build_qwen_image_control_context(encode=encode, inpaint_image=inpaint_image, inpaint_mask=mask) + + (encoded,) = encode.inputs + regenerated_rows = torch.zeros(1, 3, 8, SIDE) + kept_rows = torch.ones(1, 3, 8, SIDE) + assert torch.equal(encoded[..., :8, :], regenerated_rows) + assert torch.equal(encoded[..., 8:16, :], kept_rows) + assert torch.equal(encoded[..., 16:24, :], regenerated_rows) + assert torch.equal(encoded[..., 24:, :], kept_rows) + keep = context[0, LATENT_CHANNELS] + assert set(keep.unique().tolist()) <= {0.0, 1.0} + assert torch.equal(keep, torch.tensor([[0.0], [1.0], [0.0], [1.0]]).expand(LATENT_SIDE, LATENT_SIDE)) + + +def test_the_keep_mask_is_sampled_nearest_not_averaged() -> None: + """A one-pixel-wide white line must not smear into a grey band at latent resolution.""" + encode = _Encoder() + mask = torch.zeros(1, 1, SIDE, SIDE) + mask[..., 8, :] = 1.0 + + context = build_qwen_image_control_context(encode=encode, inpaint_image=_image(4), inpaint_mask=mask) + + keep = context[0, LATENT_CHANNELS] + assert set(keep.unique().tolist()) <= {0.0, 1.0} + assert torch.equal(keep[1], torch.zeros(LATENT_SIDE)) + assert keep.sum() == LATENT_SIDE * (LATENT_SIDE - 1) + + +@pytest.mark.parametrize( + ("kwargs", "message"), + [ + ({}, "control image, an inpaint image"), + ({"inpaint_mask": _quadrant_mask()}, "go together"), + ({"inpaint_image": _image(5)}, "go together"), + ({"inpaint_image": _image(5), "inpaint_mask": torch.zeros(1, 1, SIDE, SIDE // 2)}, "size of the inpaint image"), + ( + { + "control_image": _image(6), + "inpaint_image": _image(7)[..., : SIDE // 2], + "inpaint_mask": _quadrant_mask()[..., : SIDE // 2], + }, + "generation size", + ), + ], + ids=["nothing", "mask-alone", "image-alone", "mask-size", "frame-mismatch"], +) +def test_incomplete_or_mismatched_inputs_are_refused(kwargs, message) -> None: + with pytest.raises(ValueError, match=message): + build_qwen_image_control_context(encode=_Encoder(), **kwargs) diff --git a/tests/backend/fun_controlnet/test_qwen_image_fun_control.py b/tests/backend/fun_controlnet/test_qwen_image_fun_control.py new file mode 100644 index 00000000000..78de91abeb4 --- /dev/null +++ b/tests/backend/fun_controlnet/test_qwen_image_fun_control.py @@ -0,0 +1,276 @@ +"""The Qwen-Image Fun control branch, hooked into the real transformer, computes what VideoX-Fun's formulation does. + +`_videox_forward` is the recipe written out: the base preamble, the control chain threading its own text stream from +the base's, and an explicit loop over the base blocks adding each hint after its listed layer. It shares nothing with +the hooks beyond the modules' own forwards. Everything runs in float32 on the CPU. +""" + +import accelerate +import pytest +import torch +from diffusers.models.transformers.transformer_qwenimage import compute_text_seq_len_from_mask + +from invokeai.backend.fun_controlnet.hooks import install_fun_control, should_apply +from invokeai.backend.fun_controlnet.qwen_image import QWEN_IMAGE_FUN_CONTROL_IN_DIM, QwenImageFunControlBranch +from tests.backend.model_manager.load.state_dicts.qwen_image_fun_controlnet_keys import state_dict_keys + +LATENT_SIDE = 8 # 16 image tokens once packed 2x2 +IMAGE_TOKENS = (LATENT_SIDE // 2) ** 2 +TEXT_TOKENS = 6 +SCALE = 0.85 + + +@pytest.fixture +def inputs(tiny_qwen_image_transformer) -> dict: + """One forward's arguments, with two padded text tokens so the mask is threaded too.""" + torch.manual_seed(2) + config = tiny_qwen_image_transformer.config + mask = torch.ones(1, TEXT_TOKENS, dtype=torch.bool) + mask[0, -2:] = False + return { + "hidden_states": torch.randn(1, IMAGE_TOKENS, config.in_channels), + "encoder_hidden_states": torch.randn(1, TEXT_TOKENS, config.joint_attention_dim), + "encoder_hidden_states_mask": mask, + "timestep": torch.tensor([0.5]), + "img_shapes": [[(1, LATENT_SIDE // 2, LATENT_SIDE // 2)]], + } + + +@pytest.fixture +def control_context() -> torch.Tensor: + torch.manual_seed(3) + return torch.randn(1, IMAGE_TOKENS, QWEN_IMAGE_FUN_CONTROL_IN_DIM) + + +def _videox_forward(model, branch, control_context, scale, **inputs) -> tuple[torch.Tensor, list[torch.Tensor]]: + hidden = model.img_in(inputs["hidden_states"]) + timestep = inputs["timestep"].to(hidden.dtype) + text = model.txt_in(model.txt_norm(inputs["encoder_hidden_states"])) + text_seq_len, _, mask = compute_text_seq_len_from_mask(text, inputs["encoder_hidden_states_mask"]) + temb = model.time_text_embed(timestep, hidden) + rope = model.pos_embed(inputs["img_shapes"], max_txt_seq_len=text_seq_len, device=hidden.device) + shared = {"encoder_hidden_states_mask": mask, "temb": temb, "image_rotary_emb": rope} + + c = branch.control_img_in(control_context) + control_text = text + hints = [] + for index, block in enumerate(branch.control_blocks): + if index == 0: + c = block.before_proj(c) + hidden + control_text, c = block(hidden_states=c, encoder_hidden_states=control_text, **shared) + hints.append(block.after_proj(c)) + + for index, block in enumerate(model.transformer_blocks): + text, hidden = block(hidden_states=hidden, encoder_hidden_states=text, **shared) + if index in branch.control_layers: + hidden = hidden + hints[branch.control_layers.index(index)] * scale + return model.proj_out(model.norm_out(hidden, temb)), hints + + +def _forward(model, inputs) -> torch.Tensor: + return model(**inputs, return_dict=False)[0] + + +def _hook_count(model) -> int: + return sum(len(block._forward_hooks) + len(block._forward_pre_hooks) for block in model.transformer_blocks) + + +@torch.no_grad() +def test_the_hooked_forward_computes_the_videox_formulation( + tiny_qwen_image_transformer, tiny_branch, inputs, control_context +) -> None: + model, branch = tiny_qwen_image_transformer, tiny_branch + expected, _ = _videox_forward(model, branch, control_context, SCALE, **inputs) + plain = _forward(model, inputs) + + with install_fun_control(model, branch, control_context, scale=SCALE): + hooked = _forward(model, inputs) + + assert torch.equal(hooked, expected) + assert not torch.equal(hooked, plain) + + +@torch.no_grad() +def test_hints_land_on_the_image_stream_of_the_listed_layers_only( + tiny_qwen_image_transformer, tiny_branch, inputs, control_context +) -> None: + """Each base block's output is recorded before the hint hook sees it and after: the text stream comes through + untouched everywhere, and the image stream moves by exactly the scaled hint at the listed layers.""" + model, branch = tiny_qwen_image_transformer, tiny_branch + _, hints = _videox_forward(model, branch, control_context, SCALE, **inputs) + before: dict[int, tuple] = {} + after: dict[int, tuple] = {} + blocks = list(model.transformer_blocks) + handles = [ + block.register_forward_hook(lambda _m, _a, out, i=i: before.__setitem__(i, out)) + for i, block in enumerate(blocks) + ] + try: + with install_fun_control(model, branch, control_context, scale=SCALE): + handles += [ + block.register_forward_hook(lambda _m, _a, out, i=i: after.__setitem__(i, out)) + for i, block in enumerate(blocks) + ] + _forward(model, inputs) + finally: + for handle in handles: + handle.remove() + + for index in range(len(blocks)): + text_before, image_before = before[index] + text_after, image_after = after[index] + assert text_after is text_before + if index in branch.control_layers: + assert torch.equal(image_after, image_before + hints[branch.control_layers.index(index)] * SCALE) + else: + assert image_after is image_before + + +@torch.no_grad() +def test_scale_zero_and_an_inactive_handle_leave_the_forward_untouched( + tiny_qwen_image_transformer, tiny_branch, inputs, control_context +) -> None: + model, branch = tiny_qwen_image_transformer, tiny_branch + plain = _forward(model, inputs) + + with install_fun_control(model, branch, control_context, scale=0.0): + assert torch.equal(_forward(model, inputs), plain) + + with install_fun_control(model, branch, control_context, scale=SCALE) as hooks: + hooks.active = False + assert torch.equal(_forward(model, inputs), plain) + hooks.active = True + assert not torch.equal(_forward(model, inputs), plain) + hooks.active = False + # Nothing of the active forward is left for the inactive one. + assert torch.equal(_forward(model, inputs), plain) + + +@torch.no_grad() +def test_the_hooks_come_off_on_exit_and_when_the_body_raises( + tiny_qwen_image_transformer, tiny_branch, inputs, control_context +) -> None: + model, branch = tiny_qwen_image_transformer, tiny_branch + plain = _forward(model, inputs) + + with install_fun_control(model, branch, control_context, scale=SCALE): + assert _hook_count(model) == 1 + len(branch.control_layers) + assert _hook_count(model) == 0 + + with pytest.raises(RuntimeError, match="mid-step"): + with install_fun_control(model, branch, control_context, scale=SCALE): + _forward(model, inputs) + raise RuntimeError("mid-step") + assert _hook_count(model) == 0 + assert torch.equal(_forward(model, inputs), plain) + + +def test_a_branch_for_another_transformer_is_refused_at_install( + tiny_qwen_image_transformer, tiny_branch, control_context +) -> None: + model = tiny_qwen_image_transformer + wider = QwenImageFunControlBranch( + hidden_size=32, num_attention_heads=4, attention_head_dim=8, control_layers=(0, 2) + ) + deeper = QwenImageFunControlBranch( + hidden_size=16, num_attention_heads=2, attention_head_dim=8, control_layers=(0, 4) + ) + + with pytest.raises(ValueError, match="32 wide"), install_fun_control(model, wider, control_context, scale=1.0): + pass + with pytest.raises(ValueError, match="4 blocks"), install_fun_control(model, deeper, control_context, scale=1.0): + pass + with ( + pytest.raises(ValueError, match="132"), + install_fun_control(model, tiny_branch, control_context[..., :64], scale=1.0), + ): + pass + assert _hook_count(model) == 0 + + +def test_should_apply_counts_steps_inclusively_at_both_ends() -> None: + assert [should_apply(step, 10, 0.3, 0.8) for step in range(10)] == [False] * 3 + [True] * 6 + [False] + assert all(should_apply(step, 4, 0.0, 1.0) for step in range(4)) + + +def test_the_branch_names_and_shapes_its_tensors_as_the_checkpoint_does() -> None: + """Against the header of alibaba-pai's file: 174 tensors, `before_proj` on block 0 only. Built on the meta device, + so nothing of the 3.5 GB is allocated.""" + with accelerate.init_empty_weights(): + branch = QwenImageFunControlBranch(hidden_size=3072, num_attention_heads=24, attention_head_dim=128) + + assert {name: list(tensor.shape) for name, tensor in branch.state_dict().items()} == { + name: shape for name, (shape, _dtype) in state_dict_keys.items() + } + + +@torch.no_grad() +def test_from_state_dict_rebuilds_the_branch_that_wrote_it( + tiny_qwen_image_transformer, tiny_branch, inputs, control_context +) -> None: + model = tiny_qwen_image_transformer + state_dict = {name: tensor.clone() for name, tensor in tiny_branch.state_dict().items()} + + loaded = QwenImageFunControlBranch.from_state_dict( + state_dict, dtype=torch.float32, control_layers=(0, 2), attention_head_dim=8 + ) + + assert loaded.control_layers == (0, 2) + assert (loaded.hidden_size, loaded.control_in_dim, loaded.control_blocks[0].attn.heads) == (16, 132, 2) + assert not loaded.training + with install_fun_control(model, tiny_branch, control_context, scale=SCALE): + expected = _forward(model, inputs) + with install_fun_control(model, loaded, control_context, scale=SCALE): + assert torch.equal(_forward(model, inputs), expected) + + +@torch.no_grad() +def test_the_chain_runs_in_the_branch_dtype_and_hands_hints_back_in_the_base_dtype( + tiny_qwen_image_transformer, tiny_branch, inputs, control_context +) -> None: + """The loader follows the device's bfloat16-safe dtype while the node runs bfloat16, so a branch may be loaded in + another dtype than the activations it meets. Everything crossing into the chain is cast to the branch's dtype and + the hint back, or a modulation Linear would see a foreign dtype. Checked with a float64 branch against the float32 + base: the same arithmetic in a dtype every CPU has a GEMM for.""" + model = tiny_qwen_image_transformer + with install_fun_control(model, tiny_branch, control_context, scale=SCALE): + expected = _forward(model, inputs) + wider = QwenImageFunControlBranch.from_state_dict( + tiny_branch.state_dict(), dtype=torch.float64, control_layers=(0, 2), attention_head_dim=8 + ) + + with install_fun_control(model, wider, control_context, scale=SCALE): + hooked = _forward(model, inputs) + + assert hooked.dtype == torch.float32 + assert torch.allclose(hooked, expected, atol=1e-4, rtol=1e-4) + + +def test_from_state_dict_casts_to_the_requested_dtype(tiny_branch) -> None: + loaded = QwenImageFunControlBranch.from_state_dict( + tiny_branch.state_dict(), dtype=torch.float16, control_layers=(0, 2), attention_head_dim=8 + ) + assert {parameter.dtype for parameter in loaded.parameters()} == {torch.float16} + + +def _without(state_dict: dict, prefix: str) -> dict: + return {name: tensor for name, tensor in state_dict.items() if not name.startswith(prefix)} + + +@pytest.mark.parametrize( + ("rewrite", "message"), + [ + (lambda sd: _without(sd, "control_blocks.1."), "1 control blocks"), + (lambda sd: {**sd, "control_img_in.weight": torch.zeros(16, 64)}, "takes 64"), + (lambda sd: _without(sd, "control_img_in."), "control_img_in.weight"), + (lambda sd: _without(sd, "control_blocks.1.after_proj."), "missing"), + (lambda sd: {**sd, "control_blocks.1.before_proj.weight": torch.zeros(16, 16)}, "unexpected"), + ], + ids=["block-count", "in-dim", "no-projection", "missing-key", "stray-key"], +) +def test_from_state_dict_refuses_what_is_not_the_qwen_image_recipe(tiny_branch, rewrite, message) -> None: + state_dict = rewrite(dict(tiny_branch.state_dict())) + with pytest.raises(ValueError, match=message): + QwenImageFunControlBranch.from_state_dict( + state_dict, dtype=torch.float32, control_layers=(0, 2), attention_head_dim=8 + ) diff --git a/tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py b/tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py new file mode 100644 index 00000000000..ccf0a3bb650 --- /dev/null +++ b/tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py @@ -0,0 +1,172 @@ +"""Identification of alibaba-pai's Qwen-Image Fun-ControlNet-Union, through the config factory. + +The adapter is a VACE-style control branch: `control_img_in` projects 132 packed channels into Qwen-Image's +3072-wide stream, and five `control_blocks` copy the dual-stream `QwenImageTransformerBlock` with +`before_proj`/`after_proj` taps. Its siblings reuse the naming -- the Qwen-Image-2.1 branch is single-stream at +4096 wide, FLUX.2's keeps `control_transformer_blocks` at 6144 -- and the other Qwen-Image ControlNet designs +(InstantX, DiffSynth) share key families with FLUX ControlNets. So every case is a header written back without its +data: identification reads nothing else, and each config sees the real key names, shapes and dtypes. +""" + +from pathlib import Path + +import pytest +from pydantic import TypeAdapter + +from invokeai.backend.model_manager.configs.controlnet import ControlNet_Checkpoint_QwenImage_Config +from invokeai.backend.model_manager.configs.factory import AnyModelConfig, ModelConfigFactory +from invokeai.backend.model_manager.configs.identification_utils import NotAMatchError +from invokeai.backend.model_manager.model_on_disk import ModelOnDisk +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType +from tests.backend.model_manager.load.state_dicts import ( + qwen_image_fun_controlnet_keys, + qwen_image_instantx_controlnet_keys, +) +from tests.backend.model_manager.load.state_dicts.utils import write_header_only_safetensors + +Keys = dict[str, tuple[list[int], str]] + +FUN_FILE_NAME = "Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors" + +_OVERRIDE_FIELDS: dict[str, object] = { + "hash": "blake3:fakehash", + "path": "/fake/models/controlnet.safetensors", + "file_size": 1000, + "name": "controlnet", + "description": "test", + "source": "test", + "source_type": "path", + "key": "test-key", +} + + +def _fun_keys() -> Keys: + return dict(qwen_image_fun_controlnet_keys.state_dict_keys) + + +def _bf16(shapes: dict[str, list[int]]) -> Keys: + return {key: (shape, "BF16") for key, shape in shapes.items()} + + +# Sibling layouts with no captured header, reduced to the keys the probes read. +QWEN_IMAGE_2_1_FUN_KEYS = _bf16( + { + "control_img_in.weight": [4096, 129], + "control_img_in.bias": [4096], + "control_blocks.0.before_proj.weight": [4096, 4096], + "control_blocks.0.after_proj.weight": [4096, 4096], + "control_blocks.0.attn.to_q.weight": [4096, 4096], + "control_blocks.0.img_mlp.gate_layer.weight": [12288, 4096], + "control_blocks.0.img_mlp.proj.weight": [12288, 4096], + "control_blocks.0.img_mlp.out.weight": [4096, 12288], + "control_blocks.15.after_proj.weight": [4096, 4096], + } +) +FLUX2_FUN_KEYS = _bf16( + { + "control_img_in.weight": [6144, 260], + "control_img_in.bias": [6144], + "control_transformer_blocks.0.attn.to_q.weight": [6144, 6144], + "control_transformer_blocks.0.after_proj.weight": [6144, 6144], + } +) +Z_IMAGE_FUN_KEYS = _bf16( + { + "control_layers.0.attention.qkv.weight": [11520, 3840], + "control_layers.0.attention.out.weight": [3840, 3840], + "control_all_x_embedder.2-1.weight": [3840, 64], + "control_noise_refiner.0.attention.qkv.weight": [11520, 3840], + } +) +DIFFSYNTH_KEYS = _bf16( + { + "img_in.weight": [3072, 64], + "controlnet_blocks.0.input_proj.weight": [3072, 3072], + "controlnet_blocks.0.output_proj.weight": [3072, 3072], + "controlnet_blocks.0.x_rms.weight": [3072], + "controlnet_blocks.0.y_rms.weight": [3072], + } +) + + +def _write(tmp_path: Path, name: str, keys: Keys) -> Path: + return write_header_only_safetensors(tmp_path / name, keys) + + +def test_the_released_file_is_a_qwen_image_controlnet_and_nothing_else(tmp_path: Path) -> None: + result = ModelConfigFactory.from_model_on_disk(_write(tmp_path, FUN_FILE_NAME, _fun_keys()), allow_unknown=False) + + assert type(result.config) is ControlNet_Checkpoint_QwenImage_Config, result.details + assert result.match_count == 1, result.details + assert result.config.base is BaseModelType.QwenImage + assert result.config.type is ModelType.ControlNet + assert result.config.format is ModelFormat.Checkpoint + + +@pytest.mark.parametrize( + ("name", "preprocessor"), + [(FUN_FILE_NAME, None), ("Qwen-Image-Fun-Controlnet-Depth.safetensors", "depth_anything_image_processor")], + ids=["union", "depth"], +) +def test_the_preprocessor_is_chosen_from_the_name_as_for_every_controlnet( + tmp_path: Path, name: str, preprocessor: str | None +) -> None: + """A union adapter takes any control image, so none is pre-selected; a single-condition build picks its own.""" + config = ModelConfigFactory.from_model_on_disk(_write(tmp_path, name, _fun_keys()), allow_unknown=False).config + + assert isinstance(config, ControlNet_Checkpoint_QwenImage_Config) + assert config.default_settings is not None + assert config.default_settings.preprocessor == preprocessor + + +def test_a_stored_record_reads_back_as_a_qwen_image_controlnet(tmp_path: Path) -> None: + """The record crosses the database and the API as a plain dict, so the config has to be a member of + `AnyModelConfig` under a discriminator of its own.""" + stored = ModelConfigFactory.from_model_on_disk( + _write(tmp_path, FUN_FILE_NAME, _fun_keys()), allow_unknown=False + ).config.model_dump(mode="json") + + restored = TypeAdapter(AnyModelConfig).validate_python(stored) + + assert type(restored) is ControlNet_Checkpoint_QwenImage_Config + assert restored.base is BaseModelType.QwenImage + + +@pytest.mark.parametrize( + ("name", "keys"), + [ + ("Qwen-Image-2.1-Fun-Controlnet-Union.safetensors", QWEN_IMAGE_2_1_FUN_KEYS), + ("FLUX.2-dev-Fun-Controlnet-Union.safetensors", FLUX2_FUN_KEYS), + ("Z-Image-Turbo-Fun-Controlnet-Union.safetensors", Z_IMAGE_FUN_KEYS), + ("Qwen-Image-InstantX-ControlNet-Union.safetensors", dict(qwen_image_instantx_controlnet_keys.state_dict_keys)), + ("Qwen-Image-DiffSynth-Controlnet.safetensors", DIFFSYNTH_KEYS), + ], + ids=["qwen_image_2_1_fun", "flux2_fun", "z_image_fun", "instantx", "diffsynth"], +) +def test_the_other_control_designs_are_refused(tmp_path: Path, name: str, keys: Keys) -> None: + mod = ModelOnDisk(_write(tmp_path, name, keys)) + + with pytest.raises(NotAMatchError): + ControlNet_Checkpoint_QwenImage_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) + + +def _without_img_mod(keys: Keys) -> Keys: + return {key: value for key, value in keys.items() if ".img_mod." not in key} + + +def _with_control_img_in(keys: Keys, shape: list[int]) -> Keys: + return {**keys, "control_img_in.weight": (shape, "BF16")} + + +@pytest.mark.parametrize( + "keys", + [_without_img_mod(_fun_keys()), _with_control_img_in(_fun_keys(), [4096, 129])], + ids=["single_stream_blocks", "wider_projection"], +) +def test_a_branch_with_the_names_but_not_the_fingerprint_is_refused(tmp_path: Path, keys: Keys) -> None: + """Both halves of the fingerprint carry weight: `control_blocks` at Qwen-Image's width without `img_mod` + would be a single-stream branch, and `img_mod` behind a wider projection a branch for a wider base.""" + mod = ModelOnDisk(_write(tmp_path, FUN_FILE_NAME, keys)) + + with pytest.raises(NotAMatchError): + ControlNet_Checkpoint_QwenImage_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) diff --git a/tests/backend/model_manager/load/state_dicts/qwen_image_fun_controlnet_keys.py b/tests/backend/model_manager/load/state_dicts/qwen_image_fun_controlnet_keys.py new file mode 100644 index 00000000000..27cead31d21 --- /dev/null +++ b/tests/backend/model_manager/load/state_dicts/qwen_image_fun_controlnet_keys.py @@ -0,0 +1,193 @@ +"""Key layout of alibaba-pai's Qwen-Image Fun-ControlNet-Union (2602 build), the VACE-style control branch. + +Captured on 2026-10-18 with `scripts/capture_state_dict_fixture.py`, +which reads the header only, from +`alibaba-pai/Qwen-Image-2512-Fun-Controlnet-Union/Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors`. + +Subsetting rule: none -- every key in the file. Values are `(shape, dtype)`. + +The whole branch is 174 bf16 tensors: `control_img_in` projects 132 packed channels into Qwen-Image's +3072-wide stream, and `control_blocks.0..4` are copies of diffusers' dual-stream `QwenImageTransformerBlock` +(`img_mod`/`txt_mod`, `img_mlp.net`/`txt_mlp.net`, joint attention with `add_*_proj`) with an `after_proj` +tap on every block and a `before_proj` on block 0 only. Identification keys on the projection shape and on +`img_mod`: the Qwen-Image-2.1 branch reuses the names with 129 channels into 4096 and single-stream blocks, +FLUX.2's with 260 into 6144 under `control_transformer_blocks`. The build without `-2602` in its name has +the identical layout. +""" + +state_dict_keys: dict[str, tuple[list[int], str]] = { + "control_blocks.0.after_proj.bias": ([3072], "BF16"), + "control_blocks.0.after_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.add_k_proj.bias": ([3072], "BF16"), + "control_blocks.0.attn.add_k_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.add_q_proj.bias": ([3072], "BF16"), + "control_blocks.0.attn.add_q_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.add_v_proj.bias": ([3072], "BF16"), + "control_blocks.0.attn.add_v_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.norm_added_k.weight": ([128], "BF16"), + "control_blocks.0.attn.norm_added_q.weight": ([128], "BF16"), + "control_blocks.0.attn.norm_k.weight": ([128], "BF16"), + "control_blocks.0.attn.norm_q.weight": ([128], "BF16"), + "control_blocks.0.attn.to_add_out.bias": ([3072], "BF16"), + "control_blocks.0.attn.to_add_out.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.to_k.bias": ([3072], "BF16"), + "control_blocks.0.attn.to_k.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.to_out.0.bias": ([3072], "BF16"), + "control_blocks.0.attn.to_out.0.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.to_q.bias": ([3072], "BF16"), + "control_blocks.0.attn.to_q.weight": ([3072, 3072], "BF16"), + "control_blocks.0.attn.to_v.bias": ([3072], "BF16"), + "control_blocks.0.attn.to_v.weight": ([3072, 3072], "BF16"), + "control_blocks.0.before_proj.bias": ([3072], "BF16"), + "control_blocks.0.before_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.0.img_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.0.img_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.0.img_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.0.img_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.0.img_mod.1.bias": ([18432], "BF16"), + "control_blocks.0.img_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.0.txt_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.0.txt_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.0.txt_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.0.txt_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.0.txt_mod.1.bias": ([18432], "BF16"), + "control_blocks.0.txt_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.1.after_proj.bias": ([3072], "BF16"), + "control_blocks.1.after_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.add_k_proj.bias": ([3072], "BF16"), + "control_blocks.1.attn.add_k_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.add_q_proj.bias": ([3072], "BF16"), + "control_blocks.1.attn.add_q_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.add_v_proj.bias": ([3072], "BF16"), + "control_blocks.1.attn.add_v_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.norm_added_k.weight": ([128], "BF16"), + "control_blocks.1.attn.norm_added_q.weight": ([128], "BF16"), + "control_blocks.1.attn.norm_k.weight": ([128], "BF16"), + "control_blocks.1.attn.norm_q.weight": ([128], "BF16"), + "control_blocks.1.attn.to_add_out.bias": ([3072], "BF16"), + "control_blocks.1.attn.to_add_out.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.to_k.bias": ([3072], "BF16"), + "control_blocks.1.attn.to_k.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.to_out.0.bias": ([3072], "BF16"), + "control_blocks.1.attn.to_out.0.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.to_q.bias": ([3072], "BF16"), + "control_blocks.1.attn.to_q.weight": ([3072, 3072], "BF16"), + "control_blocks.1.attn.to_v.bias": ([3072], "BF16"), + "control_blocks.1.attn.to_v.weight": ([3072, 3072], "BF16"), + "control_blocks.1.img_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.1.img_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.1.img_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.1.img_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.1.img_mod.1.bias": ([18432], "BF16"), + "control_blocks.1.img_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.1.txt_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.1.txt_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.1.txt_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.1.txt_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.1.txt_mod.1.bias": ([18432], "BF16"), + "control_blocks.1.txt_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.2.after_proj.bias": ([3072], "BF16"), + "control_blocks.2.after_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.add_k_proj.bias": ([3072], "BF16"), + "control_blocks.2.attn.add_k_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.add_q_proj.bias": ([3072], "BF16"), + "control_blocks.2.attn.add_q_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.add_v_proj.bias": ([3072], "BF16"), + "control_blocks.2.attn.add_v_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.norm_added_k.weight": ([128], "BF16"), + "control_blocks.2.attn.norm_added_q.weight": ([128], "BF16"), + "control_blocks.2.attn.norm_k.weight": ([128], "BF16"), + "control_blocks.2.attn.norm_q.weight": ([128], "BF16"), + "control_blocks.2.attn.to_add_out.bias": ([3072], "BF16"), + "control_blocks.2.attn.to_add_out.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.to_k.bias": ([3072], "BF16"), + "control_blocks.2.attn.to_k.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.to_out.0.bias": ([3072], "BF16"), + "control_blocks.2.attn.to_out.0.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.to_q.bias": ([3072], "BF16"), + "control_blocks.2.attn.to_q.weight": ([3072, 3072], "BF16"), + "control_blocks.2.attn.to_v.bias": ([3072], "BF16"), + "control_blocks.2.attn.to_v.weight": ([3072, 3072], "BF16"), + "control_blocks.2.img_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.2.img_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.2.img_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.2.img_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.2.img_mod.1.bias": ([18432], "BF16"), + "control_blocks.2.img_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.2.txt_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.2.txt_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.2.txt_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.2.txt_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.2.txt_mod.1.bias": ([18432], "BF16"), + "control_blocks.2.txt_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.3.after_proj.bias": ([3072], "BF16"), + "control_blocks.3.after_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.add_k_proj.bias": ([3072], "BF16"), + "control_blocks.3.attn.add_k_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.add_q_proj.bias": ([3072], "BF16"), + "control_blocks.3.attn.add_q_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.add_v_proj.bias": ([3072], "BF16"), + "control_blocks.3.attn.add_v_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.norm_added_k.weight": ([128], "BF16"), + "control_blocks.3.attn.norm_added_q.weight": ([128], "BF16"), + "control_blocks.3.attn.norm_k.weight": ([128], "BF16"), + "control_blocks.3.attn.norm_q.weight": ([128], "BF16"), + "control_blocks.3.attn.to_add_out.bias": ([3072], "BF16"), + "control_blocks.3.attn.to_add_out.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.to_k.bias": ([3072], "BF16"), + "control_blocks.3.attn.to_k.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.to_out.0.bias": ([3072], "BF16"), + "control_blocks.3.attn.to_out.0.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.to_q.bias": ([3072], "BF16"), + "control_blocks.3.attn.to_q.weight": ([3072, 3072], "BF16"), + "control_blocks.3.attn.to_v.bias": ([3072], "BF16"), + "control_blocks.3.attn.to_v.weight": ([3072, 3072], "BF16"), + "control_blocks.3.img_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.3.img_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.3.img_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.3.img_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.3.img_mod.1.bias": ([18432], "BF16"), + "control_blocks.3.img_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.3.txt_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.3.txt_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.3.txt_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.3.txt_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.3.txt_mod.1.bias": ([18432], "BF16"), + "control_blocks.3.txt_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.4.after_proj.bias": ([3072], "BF16"), + "control_blocks.4.after_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.add_k_proj.bias": ([3072], "BF16"), + "control_blocks.4.attn.add_k_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.add_q_proj.bias": ([3072], "BF16"), + "control_blocks.4.attn.add_q_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.add_v_proj.bias": ([3072], "BF16"), + "control_blocks.4.attn.add_v_proj.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.norm_added_k.weight": ([128], "BF16"), + "control_blocks.4.attn.norm_added_q.weight": ([128], "BF16"), + "control_blocks.4.attn.norm_k.weight": ([128], "BF16"), + "control_blocks.4.attn.norm_q.weight": ([128], "BF16"), + "control_blocks.4.attn.to_add_out.bias": ([3072], "BF16"), + "control_blocks.4.attn.to_add_out.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.to_k.bias": ([3072], "BF16"), + "control_blocks.4.attn.to_k.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.to_out.0.bias": ([3072], "BF16"), + "control_blocks.4.attn.to_out.0.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.to_q.bias": ([3072], "BF16"), + "control_blocks.4.attn.to_q.weight": ([3072, 3072], "BF16"), + "control_blocks.4.attn.to_v.bias": ([3072], "BF16"), + "control_blocks.4.attn.to_v.weight": ([3072, 3072], "BF16"), + "control_blocks.4.img_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.4.img_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.4.img_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.4.img_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.4.img_mod.1.bias": ([18432], "BF16"), + "control_blocks.4.img_mod.1.weight": ([18432, 3072], "BF16"), + "control_blocks.4.txt_mlp.net.0.proj.bias": ([12288], "BF16"), + "control_blocks.4.txt_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "control_blocks.4.txt_mlp.net.2.bias": ([3072], "BF16"), + "control_blocks.4.txt_mlp.net.2.weight": ([3072, 12288], "BF16"), + "control_blocks.4.txt_mod.1.bias": ([18432], "BF16"), + "control_blocks.4.txt_mod.1.weight": ([18432, 3072], "BF16"), + "control_img_in.bias": ([3072], "BF16"), + "control_img_in.weight": ([3072, 132], "BF16"), +} diff --git a/tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py b/tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py new file mode 100644 index 00000000000..ac6d5eb68b5 --- /dev/null +++ b/tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py @@ -0,0 +1,63 @@ +"""Key layout of Comfy-Org's single-file InstantX Qwen-Image ControlNet-Union. + +Captured on 2026-10-18 with `scripts/capture_state_dict_fixture.py`, +which reads the header only, from +`Comfy-Org/Qwen-Image-InstantX-ControlNets/split_files/controlnet/Qwen-Image-InstantX-ControlNet-Union.safetensors`. + +Subsetting rule: `controlnet_blocks` index 0, `transformer_blocks` index 0, plus every key outside a stack. +Values are `(shape, dtype)`. + +A different design from the Fun branch: a trimmed copy of the Qwen-Image transformer itself (`img_in`, +`txt_in` at Qwen2.5-VL's 3584 width, `txt_norm`, `time_text_embed`, `transformer_blocks.N`) with +`controlnet_x_embedder` for the control latent and one `controlnet_blocks.N` output projection per block -- +the key family InstantX's FLUX ControlNets use. It has no `control_img_in`, which is what keeps it out of +the Qwen-Image Fun config. +""" + +state_dict_keys: dict[str, tuple[list[int], str]] = { + "controlnet_blocks.0.bias": ([3072], "BF16"), + "controlnet_blocks.0.weight": ([3072, 3072], "BF16"), + "controlnet_x_embedder.bias": ([3072], "BF16"), + "controlnet_x_embedder.weight": ([3072, 64], "BF16"), + "img_in.bias": ([3072], "BF16"), + "img_in.weight": ([3072, 64], "BF16"), + "time_text_embed.timestep_embedder.linear_1.bias": ([3072], "BF16"), + "time_text_embed.timestep_embedder.linear_1.weight": ([3072, 256], "BF16"), + "time_text_embed.timestep_embedder.linear_2.bias": ([3072], "BF16"), + "time_text_embed.timestep_embedder.linear_2.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.add_k_proj.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.add_k_proj.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.add_q_proj.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.add_q_proj.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.add_v_proj.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.add_v_proj.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.norm_added_k.weight": ([128], "BF16"), + "transformer_blocks.0.attn.norm_added_q.weight": ([128], "BF16"), + "transformer_blocks.0.attn.norm_k.weight": ([128], "BF16"), + "transformer_blocks.0.attn.norm_q.weight": ([128], "BF16"), + "transformer_blocks.0.attn.to_add_out.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.to_add_out.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.to_k.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.to_k.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.to_out.0.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.to_out.0.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.to_q.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.to_q.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.attn.to_v.bias": ([3072], "BF16"), + "transformer_blocks.0.attn.to_v.weight": ([3072, 3072], "BF16"), + "transformer_blocks.0.img_mlp.net.0.proj.bias": ([12288], "BF16"), + "transformer_blocks.0.img_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "transformer_blocks.0.img_mlp.net.2.bias": ([3072], "BF16"), + "transformer_blocks.0.img_mlp.net.2.weight": ([3072, 12288], "BF16"), + "transformer_blocks.0.img_mod.1.bias": ([18432], "BF16"), + "transformer_blocks.0.img_mod.1.weight": ([18432, 3072], "BF16"), + "transformer_blocks.0.txt_mlp.net.0.proj.bias": ([12288], "BF16"), + "transformer_blocks.0.txt_mlp.net.0.proj.weight": ([12288, 3072], "BF16"), + "transformer_blocks.0.txt_mlp.net.2.bias": ([3072], "BF16"), + "transformer_blocks.0.txt_mlp.net.2.weight": ([3072, 12288], "BF16"), + "transformer_blocks.0.txt_mod.1.bias": ([18432], "BF16"), + "transformer_blocks.0.txt_mod.1.weight": ([18432, 3072], "BF16"), + "txt_in.bias": ([3072], "BF16"), + "txt_in.weight": ([3072, 3584], "BF16"), + "txt_norm.weight": ([3584], "BF16"), +} diff --git a/tests/backend/model_manager/load/test_fp8_capability.py b/tests/backend/model_manager/load/test_fp8_capability.py index 08be63e0670..750b7d7dcb2 100644 --- a/tests/backend/model_manager/load/test_fp8_capability.py +++ b/tests/backend/model_manager/load/test_fp8_capability.py @@ -229,6 +229,7 @@ def test_the_declarations_are_the_backlog_and_nothing_else(self) -> None: "flux/controlnet/diffusers", "minimax-h3/main/checkpoint", "minimax-h3/main/diffusers", + "qwen-image/controlnet/checkpoint", "z-image/controlnet/checkpoint", ] diff --git a/tests/backend/model_manager/load/test_fun_controlnet_loader.py b/tests/backend/model_manager/load/test_fun_controlnet_loader.py new file mode 100644 index 00000000000..b4e4ac5a731 --- /dev/null +++ b/tests/backend/model_manager/load/test_fun_controlnet_loader.py @@ -0,0 +1,98 @@ +"""What the Qwen-Image Fun-ControlNet loader makes of a checkpoint: the geometry it reads off the tensors, the dtype +it casts to, and the quantized files it refuses rather than loads unscaled. + +Like the Z-Image ControlNet loader it builds under `init_empty_weights` and assigns the file's tensors, so an fp8 +weight with its scale dropped would become the parameter as it is (`test_z_image_control_adapter_loader.py`). No +quantized build of this adapter is published (alibaba-pai ships two dense bf16 files), so refusing costs nothing. +""" + +from pathlib import Path + +import pytest +import torch + +from invokeai.backend.fun_controlnet.qwen_image import QWEN_IMAGE_FUN_CONTROL_LAYERS, QwenImageFunControlBranch +from invokeai.backend.model_manager.configs.controlnet import ControlNet_Checkpoint_QwenImage_Config +from invokeai.backend.model_manager.load.model_loaders import fun_controlnet +from invokeai.backend.model_manager.load.model_loaders.fun_controlnet import QwenImageFunControlNetLoader +from tests.fixtures.loader_seams import Seam, prepare +from tests.fixtures.quantized_payloads import comfy_quant_marker, quantize_convrot, quantize_scaled_fp8 + +# One 128-wide head: the narrowest branch the loader's head rule accepts, with the real five-block layout. +HIDDEN = 128 +QUANTIZED_LAYER = "control_blocks.0.attn.to_q" + +SEAM = Seam( + loader=QwenImageFunControlNetLoader, + module=fun_controlnet, + entry="_load_model", + compute_dtype=torch.bfloat16, + # The loader takes its dtype from the device and never reads `self._torch_dtype`. + patches_device=True, + sets_torch_dtype=False, + casts_fp8_storage=False, +) + + +def _checkpoint() -> dict[str, torch.Tensor]: + """A float32 file with the real layout; the loader has to cast it.""" + torch.manual_seed(0) + branch = QwenImageFunControlBranch(hidden_size=HIDDEN, num_attention_heads=1, attention_head_dim=128) + return {name: tensor.detach().clone() for name, tensor in branch.state_dict().items()} + + +def _driver(monkeypatch: pytest.MonkeyPatch, tmp_path: Path, state_dict: dict[str, torch.Tensor]): + checkpoint = tmp_path / "qwen_image_fun_controlnet.safetensors" + checkpoint.touch() + config = ControlNet_Checkpoint_QwenImage_Config.model_construct(path=str(checkpoint), name="qwen-image-control") + return prepare(SEAM, monkeypatch, state_dict=state_dict), config + + +def test_a_dense_checkpoint_loads_with_its_geometry_in_the_compute_dtype(monkeypatch, tmp_path) -> None: + run, config = _driver(monkeypatch, tmp_path, _checkpoint()) + + model = run.load(config) + + assert isinstance(model, QwenImageFunControlBranch) + assert model.control_layers == QWEN_IMAGE_FUN_CONTROL_LAYERS + assert (model.hidden_size, model.control_in_dim, model.control_blocks[0].attn.heads) == (HIDDEN, 132, 1) + assert {parameter.dtype for parameter in model.parameters()} == {torch.bfloat16} + assert not model.training + + +def test_a_scaled_fp8_checkpoint_is_refused_rather_than_loaded_unscaled(monkeypatch, tmp_path) -> None: + payload = quantize_scaled_fp8(torch.randn(HIDDEN, HIDDEN)) + state_dict = _checkpoint() + state_dict[f"{QUANTIZED_LAYER}.weight"] = payload.codes + state_dict[f"{QUANTIZED_LAYER}.weight_scale"] = payload.scale + run, config = _driver(monkeypatch, tmp_path, state_dict) + + with pytest.raises(ValueError, match="quantization side channel"): + run.load(config) + + +def test_an_int8_checkpoint_is_refused_by_its_marker(monkeypatch, tmp_path) -> None: + codes, scale, _ = quantize_convrot(torch.randn(HIDDEN, 256)) + state_dict = _checkpoint() + state_dict[f"{QUANTIZED_LAYER}.weight"] = codes + state_dict[f"{QUANTIZED_LAYER}.weight_scale"] = scale + state_dict[f"{QUANTIZED_LAYER}.comfy_quant"] = comfy_quant_marker({"format": "int8_tensorwise", "convrot": True}) + run, config = _driver(monkeypatch, tmp_path, state_dict) + + with pytest.raises(ValueError, match="quantization side channel"): + run.load(config) + + +@pytest.mark.parametrize( + ("rewrite", "message"), + [ + (lambda sd: {k: v for k, v in sd.items() if not k.startswith("control_blocks.4.")}, "4 control blocks"), + (lambda sd: {**sd, "control_img_in.weight": torch.zeros(HIDDEN, 64)}, "takes 64"), + ], + ids=["four-blocks", "sixteen-channel-context"], +) +def test_another_recipe_is_refused_by_name(monkeypatch, tmp_path, rewrite, message) -> None: + run, config = _driver(monkeypatch, tmp_path, rewrite(_checkpoint())) + + with pytest.raises(ValueError, match=message): + run.load(config) diff --git a/tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors b/tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors new file mode 100644 index 00000000000..9e621d9d88d --- /dev/null +++ b/tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2fb88d8f2e0f139378043b16e4f255696d0f9a1428cd5e3cd4e4c0b91afa9796 +size 25912 diff --git a/tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/__test_metadata__.json b/tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/__test_metadata__.json new file mode 100644 index 00000000000..e61968a705d --- /dev/null +++ b/tests/model_identification/stripped_models/779c26bd-e559-4958-80ce-69a551931a26/__test_metadata__.json @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9401079bc6203272867a6d71d8b0e96cc437bc89b226dd291c9225402793df7 +size 557 From a7e04c87595cc29ab743902adbe8c7116fd419a7 Mon Sep 17 00:00:00 2001 From: Alexander Eichhorn Date: Mon, 19 Oct 2026 08:58:07 +0200 Subject: [PATCH 2/2] feat(controlnet): support the InstantX Qwen Image ControlNet Union The union file now installs as a Qwen Image ControlNet instead of a main model and feeds diffusers-style residuals to both CFG passes. Earlier installs fail to load with a pointer to Re-identify; the InstantX inpainting model is refused for now. --- .../03.Models/03.model-format-support.mdx | 4 +- .../03.Models/Local Models/qwen-image.mdx | 54 ++- .../qwen_image/qwen_image_control.py | 17 +- .../qwen_image/qwen_image_denoise.py | 174 +++++--- .../flux/controlnet/state_dict_utils.py | 11 +- .../model_manager/configs/controlnet.py | 68 ++- .../backend/model_manager/configs/main.py | 5 + .../load/model_loaders/fun_controlnet.py | 44 -- .../load/model_loaders/qwen_image.py | 9 + .../model_loaders/qwen_image_controlnet.py | 114 ++++++ .../qwen_image_controlnet_keys.py | 27 ++ .../model_manager/starter_models/__init__.py | 2 + .../starter_models/qwen_image.py | 9 + invokeai/frontend/api/openapi.json | 20 +- invokeai/frontend/api/schema.ts | 34 +- .../qwenImageControlCanvasGraphs.json | 386 ++++++++++++++++++ .../core/canvas/addControlLayers.test.ts | 32 ++ .../core/canvas/addControlLayers.ts | 17 +- .../core/canvas/compileCanvasGraph.test.ts | 30 ++ .../core/canvas/controlValidation.ts | 2 +- .../webv2/src/features/models/core/types.ts | 2 + .../webv2/src/workbench/controlAdapters.ts | 2 +- .../invoke/prepareCanvasInvocation.test.ts | 28 ++ .../canvas/invoke/prepareCanvasInvocation.ts | 1 + .../ControlLayerSettings.browser.test.tsx | 11 +- ...test_frontend_qwen_image_control_graphs.py | 33 +- .../invocations/test_qwen_image_control.py | 280 ++++++++++++- .../flux/controlnet/test_state_dict_utils.py | 5 + .../test_qwen_image_controlnet_config.py | 272 ++++++++++++ .../test_qwen_image_fun_controlnet_config.py | 172 -------- .../qwen_image_instantx_controlnet_keys.py | 4 +- .../load/test_fun_controlnet_loader.py | 98 ----- .../load/test_qwen_image_controlnet_loader.py | 248 +++++++++++ ...mage-InstantX-ControlNet-Union.safetensors | 3 + .../__test_metadata__.json | 3 + 35 files changed, 1768 insertions(+), 453 deletions(-) delete mode 100644 invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py create mode 100644 invokeai/backend/model_manager/load/model_loaders/qwen_image_controlnet.py create mode 100644 invokeai/backend/model_manager/qwen_image_controlnet_keys.py create mode 100644 tests/backend/model_manager/configs/test_qwen_image_controlnet_config.py delete mode 100644 tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py delete mode 100644 tests/backend/model_manager/load/test_fun_controlnet_loader.py create mode 100644 tests/backend/model_manager/load/test_qwen_image_controlnet_loader.py create mode 100644 tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/Qwen-Image-InstantX-ControlNet-Union.safetensors create mode 100644 tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/__test_metadata__.json diff --git a/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx b/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx index a878bc8e832..80516d85da2 100644 --- a/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx +++ b/docs/src/content/docs/Users Guide/03.Models/03.model-format-support.mdx @@ -1,7 +1,7 @@ --- title: Model Format Support description: Which file formats and quantizations InvokeAI loads for every model family, text encoder, VAE and adapter. -lastUpdated: 2026-10-18 +lastUpdated: 2026-10-19 sidebar: order: 3 --- @@ -102,7 +102,7 @@ not check, so a quantized file there fails with an unclear error or decodes inco | SDXL | ✓ (LyCORIS, Diffusers, OMI) | ✓ | IP-Adapter, T2I-Adapter, textual inversion | | FLUX.1 | ✓ (LyCORIS, Diffusers, OMI) | ✓ | Control LoRA, IP-Adapter, Redux | | FLUX.2, Z-Image | ✓ (LyCORIS, Diffusers) | Z-Image only | | -| Qwen-Image, Krea-2, Wan 2.2, Anima | ✓ (LyCORIS/kohya, including LoKR where noted on the family page) | Qwen-Image (single-file checkpoint), Anima (ControlNet-LLLite) | | +| Qwen-Image, Krea-2, Wan 2.2, Anima | ✓ (LyCORIS/kohya, including LoKR where noted on the family page) | Qwen-Image (single-file checkpoint: Fun and InstantX ControlNet Unions; InstantX Inpainting is refused), Anima (ControlNet-LLLite) | | | LTX-2, MiniMax H3 | ✓ (plain low-rank; LoKR, LoHA and DoRA are refused) | ✗ | | | SD 3, CogView4, Ideogram 4, ERNIE-Image, Qwen-Image-2.1 | ✗ | ✗ | | diff --git a/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx b/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx index 093193b3b50..db8db23ad31 100644 --- a/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx +++ b/docs/src/content/docs/Users Guide/03.Models/Local Models/qwen-image.mdx @@ -1,7 +1,7 @@ --- title: Qwen Image -description: Generate and edit images with the Qwen Image 2512 text-to-image model and the Qwen Image Edit 2511 reference-image editing model, including GGUF installs, the Lightning LoRAs and the Fun-ControlNet-Union. -lastUpdated: 2026-10-18 +description: Generate and edit images with the Qwen Image 2512 text-to-image model and the Qwen Image Edit 2511 reference-image editing model, including GGUF installs, the Lightning LoRAs and the Fun and InstantX ControlNet Unions. +lastUpdated: 2026-10-19 sidebar: order: 8 --- @@ -22,8 +22,8 @@ and only the text-to-image variant takes a [ControlNet](#controlnet). ## License -Qwen Image 2512, Qwen Image Edit 2511, the Lightning LoRAs, the Qwen2.5-VL text encoder and the Qwen Image -ControlNet Union are released under **Apache 2.0**, which allows commercial use. None of the downloads is gated. +Qwen Image 2512, Qwen Image Edit 2511, the Lightning LoRAs, the Qwen2.5-VL text encoder and both Qwen Image +ControlNet Unions are released under **Apache 2.0**, which allows commercial use. None of the downloads is gated. This is a summary, not legal advice. Read the full license on the model's HuggingFace page before using a model commercially. @@ -139,26 +139,42 @@ In the workflow editor use **Apply LoRA - Qwen Image** or **Apply LoRA Collectio ## ControlNet -The **Qwen Image ControlNet Union** starter model is alibaba-pai's *Fun-ControlNet-Union* for Qwen Image 2512 -(~3.5 GB, Apache 2.0). One model handles every condition: **Canny**, **HED**, **Depth**, **Pose**, **MLSD**, -**Scribble** and **Gray** control images, plus **inpainting**. It is trained for the text-to-image transformer: -with a Qwen Image Edit model selected, a control layer's settings and the **Invoke** button say that the -ControlNet is not compatible, and nothing is generated until the layer is disabled or the model changed. +Two ControlNets are starter models, both a single model for several conditions (~3.5 GB each, Apache 2.0): + +| Starter model | Design | Conditions | Recommended weight | +| ------------- | ------ | ---------- | ------------------ | +| **Qwen Image ControlNet Union** | alibaba-pai's *Fun-ControlNet-Union* for Qwen Image 2512 | **Canny**, **HED**, **Depth**, **Pose**, **MLSD**, **Scribble** and **Gray** control images, plus **inpainting** | `0.70` to `0.95` | +| **Qwen Image InstantX ControlNet Union** | InstantX's *ControlNet-Union*, trained on the original Qwen Image | **Canny**, **Soft Edge** (HED), **Depth** and **Pose** control images; control only | about `1.5` to `2.0` on Qwen Image 2512 (`0.80` to `1.00` on the original Qwen Image) | + +The two work differently. The Fun union is a control branch inside the transformer that reads the control image +and, when inpainting, the region being regenerated. The InstantX union is a five-block copy of the transformer that +runs beside it once per step and adds its output to the transformer's blocks; it takes the control image and +nothing else; InstantX recommends 30 steps at CFG 4 for it. InstantX trained it on the original Qwen Image, and on +Qwen Image 2512 it guides weakly at its card's `0.80` to `1.00`: a pose skeleton barely moves the figure at `1.0` +and is followed at `1.5` to `2.0`. The Fun union is trained for Qwen Image 2512 directly. InvokeAI tells the two +apart from the file on install; a copy of the InstantX union installed by an earlier version as a Qwen Image main model is fixed by +**Re-identify** in the Model Manager. InstantX's separate *Inpainting* ControlNet is not supported yet and is +refused on install. + +Both are trained for the text-to-image transformer: with a Qwen Image Edit model selected, a control layer's +settings and the **Invoke** button say that the ControlNet is not compatible, and nothing is generated until the +layer is disabled or the model changed. On the Canvas, add a **Control Layer** while a Qwen Image model is selected. Its adapter type is **Qwen Image -ControlNet** and its pixels are the control image; the layer's **Filter** turns a raster into one of the -conditions (Canny, HED, Depth Anything, DW Openpose, MLSD, Scribble or Grayscale). The layer's **Weight** is -the model's control scale: it ranges from `0` to `2`, starts at `0.85`, and `0.70` to `0.95` is the -recommended range. **Only one** Qwen Image control layer can be used per generation. +ControlNet**, its model either union, and its pixels are the control image; the layer's **Filter** turns a raster +into one of the conditions (Canny, HED, Depth Anything, DW Openpose, MLSD, Scribble or Grayscale). The layer's +**Weight** is the model's control scale: it ranges from `0` to `2` and starts at `0.85`. **Only one** Qwen Image +control layer can be used per generation. -When the Canvas inpaints or outpaints with a control layer present, the ControlNet also receives the image being -regenerated and the mask of the region as its inpainting condition. Without a control layer, inpainting and -outpainting work as before. +When the Canvas inpaints or outpaints with a Fun union layer present, the ControlNet also receives the image being +regenerated and the mask of the region as its inpainting condition. An InstantX union layer only guides the +regenerated region with its control image. Without a control layer, inpainting and outpainting work as before. In the workflow editor, the same thing is the **Qwen Image ControlNet** node feeding the **Control** input of **Denoise - Qwen Image**. Give it a control **Image**, an **Inpaint Image** together with its **Inpaint Mask** -(white is regenerated), or both. **Denoise - Qwen Image** then also needs its **VAE** input connected, which it -uses to encode these images. +(white is regenerated), or both; with the InstantX union, a control **Image** only, and the denoise refuses inpaint +inputs. **Denoise - Qwen Image** then also needs its **VAE** input connected, which it uses to encode these +images. ## PiD super-resolution decode @@ -173,7 +189,7 @@ Decoder Qwen-Image (2K to 4K)* decoders (including an int8 build of the latter) | **Main Model - Qwen Image** | Loads the transformer, VAE and Qwen VL encoder (or a component source) | | **Prompt - Qwen Image** | Encodes the prompt and any reference images | | **Denoise - Qwen Image** | Runs sampling; accepts reference latents, img2img latents, masks and a ControlNet | -| **Qwen Image ControlNet** | Configures the ControlNet Union: control image and/or inpaint image with mask, scale, step range | +| **Qwen Image ControlNet** | Configures either ControlNet Union: control image and/or inpaint image with mask (Fun only), scale, step range | | **Image to Latents - Qwen Image** | VAE encode | | **Latents to Image - Qwen Image** | VAE decode | | **Latents to Image - Qwen-Image + PiD (4x SR)** | PiD super-resolution decode | diff --git a/invokeai/app/invocations/qwen_image/qwen_image_control.py b/invokeai/app/invocations/qwen_image/qwen_image_control.py index 86404e17962..386a4b27fbb 100644 --- a/invokeai/app/invocations/qwen_image/qwen_image_control.py +++ b/invokeai/app/invocations/qwen_image/qwen_image_control.py @@ -1,4 +1,5 @@ -"""Qwen Image ControlNet: the alibaba-pai Fun-ControlNet-Union for spatial control and inpainting.""" +"""Qwen Image ControlNet: alibaba-pai's Fun-ControlNet-Union for spatial control and inpainting, or InstantX's +ControlNet-Union for spatial control.""" from typing import Optional @@ -18,7 +19,10 @@ from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType from invokeai.backend.util.qwen_image_vae import QWEN_IMAGE_VAE_MIN_TILE_SIZE -_CONTROL_SCALE_DESCRIPTION = "Strength of the control signal. Recommended range: 0.70-0.95." +_CONTROL_SCALE_DESCRIPTION = ( + "Strength of the control signal. Recommended range: 0.70-0.95 for the Fun-ControlNet-Union; for the InstantX " + "ControlNet-Union 0.80-1.00 on the original Qwen Image, about 1.5-2.0 on Qwen Image 2512." +) _BEGIN_DESCRIPTION = "When the control is first applied (% of total steps)" _END_DESCRIPTION = "When the control is last applied (% of total steps)" _TILE_SIZE_DESCRIPTION = ( @@ -28,7 +32,8 @@ class QwenImageControlField(BaseModel): - """Qwen Image Fun-ControlNet conditioning: a control image, an inpaint image with its mask, or both.""" + """Qwen Image ControlNet conditioning: a control image, an inpaint image with its mask, or both (the InstantX + ControlNet takes the control image alone).""" image_name: str | None = Field(default=None, description="The preprocessed control image (Canny, depth, pose, ...)") inpaint_image_name: str | None = Field(default=None, description="The image to inpaint") @@ -61,10 +66,12 @@ class QwenImageControlOutput(BaseInvocationOutput): classification=Classification.Prototype, ) class QwenImageControlInvocation(BaseInvocation): - """Configure the Qwen Image Fun-ControlNet-Union for spatial control, inpainting, or both. + """Configure a Qwen Image ControlNet for spatial control, inpainting, or both. Takes a preprocessed control image (Canny, HED, depth, pose, MLSD, ...) and/or an image to inpaint with its mask - (white is regenerated), plus the Qwen Image ControlNet model. Recommended control scale: 0.70-0.95. + (white is regenerated), plus the Qwen Image ControlNet model. The Fun-ControlNet-Union takes either or both + (recommended scale 0.70-0.95); the InstantX ControlNet-Union takes the control image only (0.80-1.00 on the + original Qwen Image, about 1.5-2.0 on Qwen Image 2512). """ image: Optional[ImageField] = InputField( diff --git a/invokeai/app/invocations/qwen_image/qwen_image_denoise.py b/invokeai/app/invocations/qwen_image/qwen_image_denoise.py index 6da8e44f9dc..4b10ecf6bf0 100644 --- a/invokeai/app/invocations/qwen_image/qwen_image_denoise.py +++ b/invokeai/app/invocations/qwen_image/qwen_image_denoise.py @@ -1,9 +1,10 @@ import math from contextlib import ExitStack -from typing import Callable, ClassVar, Iterator, Optional +from typing import Callable, ClassVar, Iterator, Optional, TypeAlias import torch import torchvision.transforms as tv_transforms +from diffusers.models.controlnets.controlnet_qwenimage import QwenImageControlNetModel from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformer2DModel from PIL import Image from torchvision.transforms.functional import resize as tv_resize @@ -47,6 +48,10 @@ from invokeai.backend.util.devices import TorchDevice from invokeai.backend.util.sage_attention import sage_attention_scope +QwenImageControlModel: TypeAlias = QwenImageFunControlBranch | QwenImageControlNetModel +"""Either Qwen-Image ControlNet design: the Fun branch hooked into the transformer's blocks, or the InstantX +ControlNet run beside it.""" + @invocation( "qwen_image_denoise", @@ -277,7 +282,7 @@ def _run_diffusion(self, context: InvocationContext): getattr(transformer_info.model, "zero_cond_t", False) or getattr(transformer_info.model.config, "zero_cond_t", False) ) - control_branch_info = self._load_control_branch(context, has_zero_cond_t) + control_info, control_model = self._load_control_model(context, has_zero_cond_t) # Load conditioning pos_prompt_embeds, pos_prompt_mask = self._load_text_conditioning( @@ -486,12 +491,6 @@ def _run_diffusion(self, context: InvocationContext): model_input_seq_len = noisy_seq_len + (ref_latents_packed.shape[1] if ref_latents_packed is not None else 0) transformer_config = context.models.get_config(self.transformer.transformer) - num_control_blocks = 0 - control_hidden_size = 0 - if control_branch_info is not None: - assert isinstance(control_branch_info.model, QwenImageFunControlBranch) - num_control_blocks = len(control_branch_info.model.control_blocks) - control_hidden_size = control_branch_info.model.hidden_size # The forward's activations, which the cache keeps free by offloading as much of the transformer as that # takes, plus the per-forward dequantization transient of an nvfp4 or GGUF build, alive alongside them and # invisible to the estimate. All read from the unlocked model, before the lock; the transient is zero for a @@ -503,8 +502,7 @@ def _run_diffusion(self, context: InvocationContext): image_seq_len=model_input_seq_len, text_seq_len=text_seq_len, element_size=inference_dtype.itemsize, - num_control_blocks=num_control_blocks, - control_hidden_size=control_hidden_size, + control_model=control_model, ) # Where SDPA has no fused kernel for the joint [text ; image] sequence (ROCm on Windows, MPS) it materializes # the score matrices, which the linear term above was not priced for: 24 heads x 4608^2 scores is ~1 GB at @@ -520,8 +518,8 @@ def _run_diffusion(self, context: InvocationContext): # Encoded ahead of the transformer's lock, so the VAE does not have to fit beside it. control_context: torch.Tensor | None = None - if control_branch_info is not None: - control_context = self._build_control_context(context, latent_height, latent_width) + if control_model is not None: + control_context = self._build_control_context(context, control_model, latent_height, latent_width) control_context = control_context.to(device=device, dtype=inference_dtype) with ExitStack() as exit_stack: @@ -530,24 +528,30 @@ def _run_diffusion(self, context: InvocationContext): ) assert isinstance(transformer, QwenImageTransformer2DModel) control_hooks: FunControlHooks | None = None - if control_branch_info is not None: + controlnet: QwenImageControlNetModel | None = None + if control_info is not None: assert self.control is not None and control_context is not None - # Locked with the same working memory: the transformer can no longer be offloaded, so a branch placed - # with only the default reservation would fill the room kept for the forward. - (_, control_branch) = exit_stack.enter_context( - control_branch_info.model_on_device(working_mem_bytes=working_mem_bytes) + # Locked with the same working memory: the transformer can no longer be offloaded, so a control model + # placed with only the default reservation would fill the room kept for the forward. + (_, locked_control) = exit_stack.enter_context( + control_info.model_on_device(working_mem_bytes=working_mem_bytes) ) - assert isinstance(control_branch, QwenImageFunControlBranch) - # Dtype invariant: the loader cast the branch to the device's bfloat16-safe dtype, the policy the - # transformer loaders follow, which is `inference_dtype` wherever this node runs. Should the safe - # dtype ever be another one, the branch still runs its chain in its own dtype and casts every tensor - # on the way in and the hint on the way out (`QwenImageFunControlBranch.block_runner` / `add_hint`), - # so no cache-managed module is cast here. - control_hooks = exit_stack.enter_context( - install_fun_control( - transformer, control_branch, control_context, scale=self.control.control_context_scale + if isinstance(locked_control, QwenImageControlNetModel): + # Run beside the transformer and fed what it is fed: loaded by the same dtype policy, it takes the + # same activations and hands its residuals back in the dtype the transformer adds them in. + controlnet = locked_control + else: + assert isinstance(locked_control, QwenImageFunControlBranch) + # Dtype invariant: the loader cast the branch to the device's bfloat16-safe dtype, the policy the + # transformer loaders follow, which is `inference_dtype` wherever this node runs. Should the safe + # dtype ever be another one, the branch still runs its chain in its own dtype and casts every + # tensor on the way in and the hint on the way out (`QwenImageFunControlBranch.block_runner` / + # `add_hint`), so no cache-managed module is cast here. + control_hooks = exit_stack.enter_context( + install_fun_control( + transformer, locked_control, control_context, scale=self.control.control_context_scale + ) ) - ) # Quantized weights (packed nvfp4 Linears, GGUF, SDNQ) cannot take a direct patch, so their LoRAs ride as # sidecars. Asked of the loaded module tree: a `checkpoint` build may hold packed Linears. model_is_quantized = requires_sidecar_patching(transformer, transformer_config.format) @@ -567,12 +571,12 @@ def _run_diffusion(self, context: InvocationContext): exit_stack.enter_context(sage_attention_scope()) for step_idx, t in enumerate(tqdm(timesteps_sched)): + # One gate per step: both guidance branches run with the control, or neither does. + control_active = self.control is not None and should_apply( + step_idx, total_steps, self.control.begin_step_percent, self.control.end_step_percent + ) if control_hooks is not None: - assert self.control is not None - # One gate per step: both guidance branches run with the control, or neither does. - control_hooks.active = should_apply( - step_idx, total_steps, self.control.begin_step_percent, self.control.end_step_percent - ) + control_hooks.active = control_active # The pipeline passes timestep / 1000 to the transformer timestep = t.expand(latents.shape[0]).to(inference_dtype) @@ -584,12 +588,29 @@ def _run_diffusion(self, context: InvocationContext): else: model_input = latents + # The InstantX ControlNet runs once per step, on the positive prompt, and both guidance branches add + # its residuals, already scaled: diffusers' QwenImageControlNetPipeline. Skipped outside the step range. + controlnet_block_samples: list[torch.Tensor] | None = None + if controlnet is not None and control_active: + assert self.control is not None + controlnet_block_samples = controlnet( + hidden_states=model_input, + controlnet_cond=control_context, + conditioning_scale=self.control.control_context_scale, + encoder_hidden_states=pos_prompt_embeds, + encoder_hidden_states_mask=pos_prompt_mask, + timestep=timestep / 1000, + img_shapes=img_shapes, + return_dict=False, + ) + noise_pred_cond = transformer( hidden_states=model_input, encoder_hidden_states=pos_prompt_embeds, encoder_hidden_states_mask=pos_prompt_mask, timestep=timestep / 1000, img_shapes=img_shapes, + controlnet_block_samples=controlnet_block_samples, return_dict=False, )[0] # Only keep the noisy-latent portion of the output @@ -602,6 +623,7 @@ def _run_diffusion(self, context: InvocationContext): encoder_hidden_states_mask=neg_prompt_mask, timestep=timestep / 1000, img_shapes=img_shapes, + controlnet_block_samples=controlnet_block_samples, return_dict=False, )[0] noise_pred_uncond = noise_pred_uncond[:, :noisy_seq_len] @@ -638,29 +660,41 @@ def _run_diffusion(self, context: InvocationContext): latents = latents.unsqueeze(2) return latents - def _load_control_branch(self, context: InvocationContext, has_zero_cond_t: bool) -> LoadedModel | None: - """The control branch in RAM, ahead of the transformer's lock so the reservation can size its hints.""" + def _load_control_model( + self, context: InvocationContext, has_zero_cond_t: bool + ) -> tuple[LoadedModel, QwenImageControlModel] | tuple[None, None]: + """The ControlNet in RAM, and the model it holds, ahead of the transformer's lock so the reservation can size + what the ControlNet keeps alive.""" if self.control is None: - return None + return None, None if self.vae is None: raise ValueError( "Qwen Image ControlNet needs the VAE that encodes its images: connect one to the 'vae' input." ) if self.reference_latents is not None: raise ValueError("Qwen Image ControlNet cannot be combined with reference latents.") - # The Fun branch was trained beside the generation transformer. An Edit transformer takes a - # [noisy ; reference] sequence and modulates the two apart (zero_cond_t), a layout the branch never saw. + # Both ControlNets were trained beside the generation transformer. An Edit transformer takes a + # [noisy ; reference] sequence and modulates the two apart (zero_cond_t), a layout neither ever saw. if has_zero_cond_t: raise ValueError( "Qwen Image ControlNet applies to the Qwen Image generation transformer, not to an Edit transformer." ) - control_branch_info = context.models.load(self.control.control_model) - if not isinstance(control_branch_info.model, QwenImageFunControlBranch): + control_info = context.models.load(self.control.control_model) + control_model = control_info.model + if isinstance(control_model, QwenImageControlNetModel): + # Its control input is the control image's latent and nothing else: no mask or masked-image channels + # an inpainting condition could go into. + if self.control.inpaint_image_name is not None or self.control.inpaint_mask_name is not None: + raise ValueError( + f"'{self.control.control_model.name}' is an InstantX Qwen Image ControlNet, which takes a control " + "image only and has no inpainting condition: disconnect the inpaint image and mask." + ) + elif not isinstance(control_model, QwenImageFunControlBranch): raise TypeError( f"Expected a Qwen Image ControlNet for '{self.control.control_model.name}', " - f"got {type(control_branch_info.model).__name__}." + f"got {type(control_model).__name__}." ) - return control_branch_info + return control_info, control_model @staticmethod def _estimate_working_memory( @@ -668,8 +702,7 @@ def _estimate_working_memory( text_seq_len: int, element_size: int, *, - num_control_blocks: int = 0, - control_hidden_size: int = 0, + control_model: QwenImageControlModel | None = None, ) -> int: """Peak transformer activations, in bytes, for the model cache to keep free. @@ -678,15 +711,31 @@ def _estimate_working_memory( for the allocator. The per-token term is a bf16 figure and scales with `element_size`, the compute dtype's width. The guidance branches run one after the other, so CFG adds nothing to the peak. - A control branch runs its blocks over the image sequence and keeps one hint per block alive until the last - listed base layer has consumed it. `num_control_blocks + 4` hint-sized tensors is what Z-Image measured for - its adapter over the plain forward (`z_image_denoise.py`), pending the same measurement here. + A ControlNet adds image-sized tensors (one batch item, `image_seq_len` tokens at its width): + + - The Fun branch runs its blocks over the image sequence and keeps one hint per block alive until the last + listed base layer has consumed it. `blocks + 4` is what Z-Image measured for its adapter over the plain + forward (`z_image_denoise.py`), pending the same measurement here. + - The InstantX ControlNet adds no fitted coefficient, only what provably stays alive. It runs its forward + before the transformer's: its blocks are the transformer's at the same joint sequence and never run beside + them, so their activations are inside the base term, and so is the transient at the end of its forward + (block outputs, projections, scaled copies: three image-sized tensors per block, under a tenth of the + per-token base at Qwen-Image's width). What stays alive through both guidance forwards is the list of + scaled residuals, one per block: exactly `blocks` tensors. """ mib, gib = 1024**2, 1024**3 width = element_size / 2 estimated = int((image_seq_len + text_seq_len) * 0.25 * mib * width) + gib - if num_control_blocks: - estimated += (num_control_blocks + 4) * image_seq_len * control_hidden_size * element_size + if control_model is None: + return estimated + if isinstance(control_model, QwenImageFunControlBranch): + estimated += ( + (len(control_model.control_blocks) + 4) * image_seq_len * control_model.hidden_size * element_size + ) + else: + # The alias's other member. Not `elif` + `assert_never`: mypy cannot narrow a diffusers model class out of + # a union, so the remainder would never type as `Never`. + estimated += len(control_model.controlnet_blocks) * image_seq_len * control_model.inner_dim * element_size return estimated @staticmethod @@ -713,8 +762,12 @@ def _attention_score_bytes( via_diffusers_dispatch=True, ) - def _build_control_context(self, context: InvocationContext, latent_height: int, latent_width: int) -> torch.Tensor: - """The packed ``(1, S_img, 132)`` control context at the generation size, from the control field's images.""" + def _build_control_context( + self, context: InvocationContext, control_model: QwenImageControlModel, latent_height: int, latent_width: int + ) -> torch.Tensor: + """The packed control context at the generation size, from the control field's images, as ``control_model`` + takes it: ``(1, S_img, 132)`` control, keep-mask and masked-image latents for the Fun branch, ``(1, S_img, 64)`` + the control image's latents alone for the InstantX ControlNet (diffusers' QwenImageControlNetPipeline).""" assert self.control is not None and self.vae is not None control = self.control vae_info = context.models.load(self.vae.vae) @@ -734,14 +787,19 @@ def pixels(image_name: str, mode: str) -> torch.Tensor: # (1, C, H, W): pixels in [-1, 1], a mask in [0, 1]. return image_resized_to_grid_as_tensor(image, normalize=mode == "RGB", multiple_of=16).unsqueeze(0) - context_4d = build_qwen_image_control_context( - encode=encode, - control_image=pixels(control.image_name, "RGB") if control.image_name is not None else None, - inpaint_image=( - pixels(control.inpaint_image_name, "RGB") if control.inpaint_image_name is not None else None - ), - inpaint_mask=pixels(control.inpaint_mask_name, "L") if control.inpaint_mask_name is not None else None, - ) + if isinstance(control_model, QwenImageFunControlBranch): + context_4d = build_qwen_image_control_context( + encode=encode, + control_image=pixels(control.image_name, "RGB") if control.image_name is not None else None, + inpaint_image=( + pixels(control.inpaint_image_name, "RGB") if control.inpaint_image_name is not None else None + ), + inpaint_mask=pixels(control.inpaint_mask_name, "L") if control.inpaint_mask_name is not None else None, + ) + else: + # The InstantX ControlNet, the alias's other member (see `_estimate_working_memory`). + assert control.image_name is not None + context_4d = encode(pixels(control.image_name, "RGB")) return self._pack_latents(context_4d, 1, context_4d.shape[1], latent_height, latent_width) def _build_step_callback(self, context: InvocationContext) -> Callable[[PipelineIntermediateState], None]: diff --git a/invokeai/backend/flux/controlnet/state_dict_utils.py b/invokeai/backend/flux/controlnet/state_dict_utils.py index 87eae5a96bc..6f9f4ee6487 100644 --- a/invokeai/backend/flux/controlnet/state_dict_utils.py +++ b/invokeai/backend/flux/controlnet/state_dict_utils.py @@ -3,6 +3,7 @@ import torch from invokeai.backend.flux.model import FluxParams +from invokeai.backend.model_manager.qwen_image_controlnet_keys import is_qwen_image_instantx_controlnet def is_state_dict_xlabs_controlnet(sd: dict[str | int, Any]) -> bool: @@ -26,7 +27,7 @@ def is_state_dict_xlabs_controlnet(sd: dict[str | int, Any]) -> bool: def is_state_dict_instantx_controlnet(sd: dict[str | int, Any]) -> bool: - """Is the state dict for an InstantX ControlNet model? + """Is the state dict for an InstantX FLUX ControlNet model? This is intended to be a reasonably high-precision detector, but it is not guaranteed to have perfect precision. """ @@ -38,9 +39,11 @@ def is_state_dict_instantx_controlnet(sd: dict[str | int, Any]) -> bool: "controlnet_x_embedder.weight", } - if expected_keys.issubset(sd.keys()): - return True - return False + if not expected_keys.issubset(sd.keys()): + return False + # InstantX's Qwen-Image ControlNets use the same names over Qwen-Image's own blocks. ComfyUI tells the two apart + # the same way, before its FLUX fallback. + return not is_qwen_image_instantx_controlnet(sd) def _fuse_weights(*t: torch.Tensor) -> torch.Tensor: diff --git a/invokeai/backend/model_manager/configs/controlnet.py b/invokeai/backend/model_manager/configs/controlnet.py index 2a3ab146b16..277f98da394 100644 --- a/invokeai/backend/model_manager/configs/controlnet.py +++ b/invokeai/backend/model_manager/configs/controlnet.py @@ -12,6 +12,7 @@ ) from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base, Config_Base, Diffusers_Config_Base from invokeai.backend.model_manager.configs.identification_utils import ( + InvalidMatchError, NotAMatchError, common_config_paths, get_config_dict_or_raise, @@ -22,6 +23,7 @@ state_dict_has_any_keys_starting_with, ) from invokeai.backend.model_manager.model_on_disk import ModelOnDisk +from invokeai.backend.model_manager.qwen_image_controlnet_keys import is_qwen_image_instantx_controlnet from invokeai.backend.model_manager.taxonomy import ( BaseModelType, ModelFormat, @@ -300,21 +302,56 @@ def _has_qwen_image_fun_control_keys(state_dict: dict) -> bool: return "control_blocks.0.img_mod.1.weight" in state_dict +QwenImageControlArchitecture = Literal["fun_union", "instantx_union"] +"""The two Qwen-Image ControlNet designs, which share a config and a loader but not a recipe. + +`fun_union` is alibaba-pai's branch hooked into the transformer's blocks, conditioned on control and inpaint latents; +`instantx_union` is InstantX's five-block copy of the transformer run beside it, conditioned on control latents only. +""" + +# InstantX's `controlnet_x_embedder` projects the 64 packed features of a 16-channel latent into Qwen-Image's +# 3072-wide stream; its inpainting sibling adds the 4 packed features of a mask (68). +_QWEN_IMAGE_INSTANTX_WIDTH = 3072 +_QWEN_IMAGE_INSTANTX_CONTROL_FEATURES = 64 + + +def _qwen_image_instantx_control_features(state_dict: dict) -> int | None: + """The features per token an InstantX-layout Qwen-Image ControlNet takes, or None when it is not one. + + The key signature is shared with the probes that have to refuse the file (`qwen_image_controlnet_keys.py`); the + width is what makes it a ControlNet for this base. + """ + if not is_qwen_image_instantx_controlnet(state_dict): + return None + shape = getattr(state_dict["controlnet_x_embedder.weight"], "shape", None) + if shape is None or len(shape) != 2 or shape[0] != _QWEN_IMAGE_INSTANTX_WIDTH: + return None + return int(shape[1]) + + class ControlNet_Checkpoint_QwenImage_Config(Checkpoint_Config_Base, Config_Base): - """Model config for Qwen-Image Fun-ControlNet adapter models (Safetensors checkpoint). + """Model config for Qwen-Image ControlNet models (Safetensors checkpoint), in either of two designs. - Qwen-Image Fun-ControlNets are standalone adapters containing only the control branch - (control_img_in, control_blocks) that extends the base Qwen-Image transformer with spatial - conditioning capabilities. + alibaba-pai's Fun-ControlNet-Union is a control branch (control_img_in, control_blocks) hooked into the base + Qwen-Image transformer. Supports Canny, HED, Depth, Pose, MLSD, Scribble, Gray and inpainting; recommended + control_context_scale 0.70-0.95. - Supports: Canny, HED, Depth, Pose, MLSD, Scribble, Gray, inpainting. - Recommended control_context_scale: 0.70-0.95. + InstantX's ControlNet-Union is a five-block copy of the transformer (controlnet_x_embedder, transformer_blocks, + controlnet_blocks) whose block outputs are added to the base image stream. Supports Canny, Soft Edge, Depth and + Pose; recommended control_context_scale 0.80-1.00 on the original Qwen Image it was trained on, about 1.5-2.0 on + Qwen Image 2512. It takes no inpainting condition. """ type: Literal[ModelType.ControlNet] = Field(default=ModelType.ControlNet) format: Literal[ModelFormat.Checkpoint] = Field(default=ModelFormat.Checkpoint) base: Literal[BaseModelType.QwenImage] = Field(default=BaseModelType.QwenImage) default_settings: ControlAdapterDefaultSettings | None = Field(None) + control_architecture: QwenImageControlArchitecture = Field( + default="fun_union", + description="Which Qwen-Image ControlNet design the file holds: 'fun_union' (alibaba-pai Fun-ControlNet-Union, " + "control and inpainting) or 'instantx_union' (InstantX ControlNet-Union, control only). Records written " + "before the field existed are Fun-ControlNets.", + ) @classmethod def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) -> Self: @@ -322,10 +359,23 @@ def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) - raise_for_override_fields(cls, override_fields) - if not _has_qwen_image_fun_control_keys(mod.load_state_dict()): - raise NotAMatchError("state dict does not look like a Qwen-Image Fun-ControlNet") + architecture = cls._get_control_architecture_or_raise(mod.load_state_dict()) + return cls(**{**override_fields, "control_architecture": architecture}) - return cls(**override_fields) + @classmethod + def _get_control_architecture_or_raise(cls, state_dict: dict) -> QwenImageControlArchitecture: + if _has_qwen_image_fun_control_keys(state_dict): + return "fun_union" + features = _qwen_image_instantx_control_features(state_dict) + if features is None: + raise NotAMatchError("state dict does not look like a Qwen-Image Fun or InstantX ControlNet") + if features != _QWEN_IMAGE_INSTANTX_CONTROL_FEATURES: + # Recognised and refused, so the installer shows why instead of registering a model nothing can run. + raise InvalidMatchError( + "This is the InstantX Qwen-Image inpainting ControlNet, which Invoke does not support yet. Install the " + "InstantX Qwen-Image ControlNet Union instead." + ) + return "instantx_union" def _has_anima_lllite_keys(state_dict: dict) -> bool: diff --git a/invokeai/backend/model_manager/configs/main.py b/invokeai/backend/model_manager/configs/main.py index bd297396714..0960e896444 100644 --- a/invokeai/backend/model_manager/configs/main.py +++ b/invokeai/backend/model_manager/configs/main.py @@ -46,6 +46,7 @@ ) from invokeai.backend.model_manager.configs.qwen3_encoder import _SDNQ_LOADABLE_QWEN_ARCHITECTURES from invokeai.backend.model_manager.model_on_disk import ModelOnDisk +from invokeai.backend.model_manager.qwen_image_controlnet_keys import is_qwen_image_instantx_controlnet from invokeai.backend.model_manager.taxonomy import ( AnimaVariantType, BaseModelType, @@ -2217,6 +2218,10 @@ def _has_qwen_image_keys(state_dict: dict[str | int, Any]) -> bool: and has_txt_norm and has_img_in and not has_context_embedder + # InstantX's Qwen-Image ControlNet is a trimmed copy of this transformer, `img_in`/`txt_in`/`txt_norm` + # included; the ControlNet config claims it. Asked of the stripped keys, as the loader asks: a prefixed copy + # identified as a main model would be refused at load, and identified as one again by Re-identify. + and not is_qwen_image_instantx_controlnet(set(keys)) and not _has_qwen_image21_keys(state_dict) ) diff --git a/invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py b/invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py deleted file mode 100644 index da58d7b2521..00000000000 --- a/invokeai/backend/model_manager/load/model_loaders/fun_controlnet.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Loaders for Fun-ControlNet branches (alibaba-pai VideoX-Fun); today the Qwen-Image Fun-ControlNet-Union.""" - -from pathlib import Path -from typing import Optional - -from safetensors.torch import load_file - -from invokeai.backend.fun_controlnet.qwen_image import QwenImageFunControlBranch -from invokeai.backend.model_manager.configs.base import Checkpoint_Config_Base -from invokeai.backend.model_manager.configs.factory import AnyModelConfig -from invokeai.backend.model_manager.load.fp8_capability import Unimplemented -from invokeai.backend.model_manager.load.load_default import ModelLoader -from invokeai.backend.model_manager.load.model_loader_registry import ModelLoaderRegistry -from invokeai.backend.model_manager.taxonomy import AnyModel, BaseModelType, ModelFormat, ModelType, SubModelType -from invokeai.backend.quantization.fp8_scaled import reject_quantized_side_channel -from invokeai.backend.util.devices import TorchDevice - - -@ModelLoaderRegistry.register( - base=BaseModelType.QwenImage, - type=ModelType.ControlNet, - format=ModelFormat.Checkpoint, - fp8_storage=Unimplemented( - "the branch is cast to the compute dtype at load and runs as its own module tree, so the layerwise cast would " - "fit; at 3.5 GB in bf16 it is worth closing" - ), -) -class QwenImageFunControlNetLoader(ModelLoader): - """Loads the Qwen-Image Fun-ControlNet-Union branch from its safetensors file. - - The file carries no config: the branch's geometry is read off its tensors and the base-layer map is the family's - constant (`QWEN_IMAGE_FUN_CONTROL_LAYERS`). - """ - - def _load_model(self, config: AnyModelConfig, submodel_type: Optional[SubModelType] = None) -> AnyModel: - path = Path(config.path) - if not isinstance(config, Checkpoint_Config_Base): - raise ValueError("Only checkpoint configs are supported here.") - sd = load_file(path) - # Before the geometry probe: the shapes it reads mean nothing on a packed weight, and no scale is folded here. - reject_quantized_side_channel(sd, f"Qwen Image ControlNet checkpoint {path.name}") - return QwenImageFunControlBranch.from_state_dict( - sd, dtype=TorchDevice.choose_bfloat16_safe_dtype(self._torch_device) - ) diff --git a/invokeai/backend/model_manager/load/model_loaders/qwen_image.py b/invokeai/backend/model_manager/load/model_loaders/qwen_image.py index 1c7e6bb7ff7..275082d91f4 100644 --- a/invokeai/backend/model_manager/load/model_loaders/qwen_image.py +++ b/invokeai/backend/model_manager/load/model_loaders/qwen_image.py @@ -22,6 +22,7 @@ _strip_quantization_metadata, ) from invokeai.backend.model_manager.load.model_loaders.generic_diffusers import GenericDiffusersLoader +from invokeai.backend.model_manager.qwen_image_controlnet_keys import is_qwen_image_instantx_controlnet from invokeai.backend.model_manager.taxonomy import ( AnyModel, BaseModelType, @@ -283,6 +284,14 @@ def _load_from_singlefile(self, config: AnyModelConfig) -> AnyModel: sd = load_file(str(model_path)) sd = CheckpointPrefix.detect(sd).strip(sd) + # Earlier versions identified InstantX's Qwen-Image ControlNet, a trimmed copy of this transformer, as a main + # model. Such a record still exists; the file only needs identifying again. + if is_qwen_image_instantx_controlnet(sd): + raise ValueError( + f"'{config.name}' is a Qwen Image ControlNet, not a main model: an earlier version of Invoke " + "installed it as one. Run Re-identify model on it in the Model Manager to fix the record, then pick " + "it in a control layer." + ) # Comfy's nvfp4 build keeps the image stream's attention and MLP in nvfp4, beside scaled fp8. Take those layers # out before the fold: `_dequantize_comfyui_fp8` multiplies every `.weight_scale` into its weight, nvfp4's diff --git a/invokeai/backend/model_manager/load/model_loaders/qwen_image_controlnet.py b/invokeai/backend/model_manager/load/model_loaders/qwen_image_controlnet.py new file mode 100644 index 00000000000..f2001169199 --- /dev/null +++ b/invokeai/backend/model_manager/load/model_loaders/qwen_image_controlnet.py @@ -0,0 +1,114 @@ +"""The loader for Qwen-Image ControlNets, in either design the config records: alibaba-pai's Fun-ControlNet-Union +branch or InstantX's ControlNet-Union.""" + +from collections.abc import Mapping +from pathlib import Path +from typing import Optional, assert_never + +import accelerate +import torch +from diffusers.models.controlnets.controlnet_qwenimage import QwenImageControlNetModel +from safetensors.torch import load_file + +from invokeai.backend.fun_controlnet.qwen_image import QwenImageFunControlBranch +from invokeai.backend.model_manager.configs.controlnet import ControlNet_Checkpoint_QwenImage_Config +from invokeai.backend.model_manager.configs.factory import AnyModelConfig +from invokeai.backend.model_manager.load.fp8_capability import Unimplemented +from invokeai.backend.model_manager.load.load_default import ModelLoader +from invokeai.backend.model_manager.load.model_loader_registry import ModelLoaderRegistry +from invokeai.backend.model_manager.taxonomy import AnyModel, BaseModelType, ModelFormat, ModelType, SubModelType +from invokeai.backend.quantization.fp8_scaled import reject_quantized_side_channel +from invokeai.backend.util.devices import TorchDevice + +# Qwen-Image's RoPE splits a 128-wide head into frame, height and width axes. The ControlNet runs its own RoPE over the +# same positions as the transformer and the file does not record the split, so it is a constant of the family. +QWEN_IMAGE_AXES_DIMS_ROPE = (16, 56, 56) + + +def load_qwen_image_instantx_controlnet( + sd: Mapping[str, torch.Tensor], *, dtype: torch.dtype +) -> QwenImageControlNetModel: + """Build the `QwenImageControlNetModel` the checkpoint describes and load it strictly, cast to ``dtype``. + + The geometry is read off the tensors: the width and latent features from `img_in`, the text width from `txt_in`, + the head width from the query norm, the block count from the highest `controlnet_blocks.N` index. A control input + wider than the latent is the inpainting layout, whose extra mask features nothing here produces, so it is refused. + """ + required = ( + "img_in.weight", + "txt_in.weight", + "controlnet_x_embedder.weight", + "transformer_blocks.0.attn.norm_q.weight", + ) + absent = [key for key in required if key not in sd] + if absent: + raise ValueError(f"Not an InstantX Qwen Image ControlNet checkpoint: {', '.join(absent)} missing.") + inner_dim, in_channels = sd["img_in.weight"].shape + control_features = sd["controlnet_x_embedder.weight"].shape[1] + if control_features != in_channels: + raise ValueError( + f"This InstantX Qwen Image ControlNet takes {control_features} control features per token, {in_channels} " + "for the latent plus a mask: the inpainting layout, which is not supported yet." + ) + head_dim = sd["transformer_blocks.0.attn.norm_q.weight"].shape[0] + if head_dim != sum(QWEN_IMAGE_AXES_DIMS_ROPE) or inner_dim % head_dim: + raise ValueError( + f"A {inner_dim}-wide ControlNet with {head_dim}-wide attention heads is not Qwen-Image's geometry " + f"({sum(QWEN_IMAGE_AXES_DIMS_ROPE)}-wide heads)." + ) + block_indices = { + int(index) for key in sd if key.startswith("controlnet_blocks.") and (index := key.split(".")[1]).isdigit() + } + num_layers = max(block_indices, default=-1) + 1 + if num_layers == 0: + raise ValueError("Not an InstantX Qwen Image ControlNet checkpoint: it has no `controlnet_blocks`.") + + with accelerate.init_empty_weights(): + model = QwenImageControlNetModel( + in_channels=in_channels, + num_layers=num_layers, + attention_head_dim=head_dim, + num_attention_heads=inner_dim // head_dim, + joint_attention_dim=sd["txt_in.weight"].shape[1], + axes_dims_rope=QWEN_IMAGE_AXES_DIMS_ROPE, + ) + missing, unexpected = model.load_state_dict(dict(sd), strict=False, assign=True) + if missing or unexpected: + raise ValueError( + "This checkpoint does not match the InstantX Qwen Image ControlNet layout: " + f"missing {sorted(missing)[:5]}, unexpected {sorted(unexpected)[:5]}." + ) + return model.to(dtype=dtype).eval() + + +@ModelLoaderRegistry.register( + base=BaseModelType.QwenImage, + type=ModelType.ControlNet, + format=ModelFormat.Checkpoint, + fp8_storage=Unimplemented( + "both designs are cast to the compute dtype at load and run as their own module trees, so the layerwise cast " + "would fit; at 3.5 GB in bf16 each it is worth closing" + ), +) +class QwenImageControlNetLoader(ModelLoader): + """Loads a Qwen-Image ControlNet from its safetensors file, in the design its record names. + + Neither file carries a config: the geometry is read off the tensors, and the Fun branch's base-layer map is the + family's constant (`QWEN_IMAGE_FUN_CONTROL_LAYERS`). + """ + + def _load_model(self, config: AnyModelConfig, submodel_type: Optional[SubModelType] = None) -> AnyModel: + if not isinstance(config, ControlNet_Checkpoint_QwenImage_Config): + raise ValueError("Only Qwen Image ControlNet checkpoint configs are supported here.") + path = Path(config.path) + sd = load_file(path) + # Before the geometry probe: the shapes it reads mean nothing on a packed weight, and no scale is folded here. + reject_quantized_side_channel(sd, f"Qwen Image ControlNet checkpoint {path.name}") + dtype = TorchDevice.choose_bfloat16_safe_dtype(self._torch_device) + match config.control_architecture: + case "fun_union": + return QwenImageFunControlBranch.from_state_dict(sd, dtype=dtype) + case "instantx_union": + return load_qwen_image_instantx_controlnet(sd, dtype=dtype) + case _: + assert_never(config.control_architecture) diff --git a/invokeai/backend/model_manager/qwen_image_controlnet_keys.py b/invokeai/backend/model_manager/qwen_image_controlnet_keys.py new file mode 100644 index 00000000000..7f11ea0c167 --- /dev/null +++ b/invokeai/backend/model_manager/qwen_image_controlnet_keys.py @@ -0,0 +1,27 @@ +"""The key signature of InstantX's Qwen-Image ControlNets, as one predicate. + +The layout is diffusers' `QwenImageControlNetModel`: a trimmed copy of the Qwen-Image transformer (`img_in`, `txt_in`, +`txt_norm`, `transformer_blocks.N`) plus `controlnet_x_embedder` and one `controlnet_blocks.N` projection per block. +That puts it inside two other probes' nets: the FLUX InstantX ControlNet probe reads the same `controlnet_*` names, and +the Qwen-Image main model probe the same `img_in`/`txt_in`/`txt_norm`. Both have to refuse exactly what the Qwen-Image +ControlNet config claims, and the main checkpoint loader has to recognise a file an earlier version recorded as a main +model, so all four read the signature here rather than restating it. + +Imports nothing, like `checkpoint_prefix.py`: identification and the FLUX state-dict utilities both reach it. +""" + +from collections.abc import Container + +QWEN_IMAGE_INSTANTX_CONTROLNET_KEYS = ( + "controlnet_x_embedder.weight", + "controlnet_blocks.0.weight", + # Qwen-Image's dual-stream block and text input norm: a FLUX ControlNet has `norm1`/`ff` blocks and a + # `context_embedder` instead. + "transformer_blocks.0.img_mod.1.weight", + "txt_norm.weight", +) + + +def is_qwen_image_instantx_controlnet(state_dict: Container[object]) -> bool: + """Whether the state dict has InstantX's Qwen-Image ControlNet layout, its inpainting variant included.""" + return all(key in state_dict for key in QWEN_IMAGE_INSTANTX_CONTROLNET_KEYS) diff --git a/invokeai/backend/model_manager/starter_models/__init__.py b/invokeai/backend/model_manager/starter_models/__init__.py index 866181eb078..1aff6293ed8 100644 --- a/invokeai/backend/model_manager/starter_models/__init__.py +++ b/invokeai/backend/model_manager/starter_models/__init__.py @@ -213,6 +213,7 @@ qwen_image_gguf_q4_k_m, qwen_image_gguf_q6_k, qwen_image_gguf_q8_0, + qwen_image_instantx_controlnet_union, qwen_image_lightning_4step, qwen_image_lightning_8step, qwen_image_vae, @@ -463,6 +464,7 @@ qwen_image_lightning_4step, qwen_image_lightning_8step, qwen_image_fun_controlnet_union, + qwen_image_instantx_controlnet_union, flux_krea, flux_krea_quantized, z_image_turbo, diff --git a/invokeai/backend/model_manager/starter_models/qwen_image.py b/invokeai/backend/model_manager/starter_models/qwen_image.py index 028be0b828c..41c089ca817 100644 --- a/invokeai/backend/model_manager/starter_models/qwen_image.py +++ b/invokeai/backend/model_manager/starter_models/qwen_image.py @@ -206,3 +206,12 @@ "control images, plus inpainting. Works best at weights 0.70-0.95. Apache-2.0. ~3.5GB", type=ModelType.ControlNet, ) +qwen_image_instantx_controlnet_union = StarterModel( + name="Qwen Image InstantX ControlNet Union", + base=BaseModelType.QwenImage, + source="https://huggingface.co/Comfy-Org/Qwen-Image-InstantX-ControlNets/resolve/main/split_files/controlnet/Qwen-Image-InstantX-ControlNet-Union.safetensors", + description="InstantX's ControlNet for Qwen Image supporting Canny, Soft Edge, Depth and Pose control images; " + "no inpainting. Trained on the original Qwen Image: on Qwen Image 2512 use weights of about 1.5-2.0. Apache-2.0. " + "~3.5GB", + type=ModelType.ControlNet, +) diff --git a/invokeai/frontend/api/openapi.json b/invokeai/frontend/api/openapi.json index 668b98fee50..d2c0f10c509 100644 --- a/invokeai/frontend/api/openapi.json +++ b/invokeai/frontend/api/openapi.json @@ -28156,6 +28156,13 @@ "type": "null" } ] + }, + "control_architecture": { + "type": "string", + "enum": ["fun_union", "instantx_union"], + "title": "Control Architecture", + "description": "Which Qwen-Image ControlNet design the file holds: 'fun_union' (alibaba-pai Fun-ControlNet-Union, control and inpainting) or 'instantx_union' (InstantX ControlNet-Union, control only). Records written before the field existed are Fun-ControlNets.", + "default": "fun_union" } }, "type": "object", @@ -28175,10 +28182,11 @@ "type", "format", "base", - "default_settings" + "default_settings", + "control_architecture" ], "title": "ControlNet_Checkpoint_QwenImage_Config", - "description": "Model config for Qwen-Image Fun-ControlNet adapter models (Safetensors checkpoint).\n\nQwen-Image Fun-ControlNets are standalone adapters containing only the control branch\n(control_img_in, control_blocks) that extends the base Qwen-Image transformer with spatial\nconditioning capabilities.\n\nSupports: Canny, HED, Depth, Pose, MLSD, Scribble, Gray, inpainting.\nRecommended control_context_scale: 0.70-0.95." + "description": "Model config for Qwen-Image ControlNet models (Safetensors checkpoint), in either of two designs.\n\nalibaba-pai's Fun-ControlNet-Union is a control branch (control_img_in, control_blocks) hooked into the base\nQwen-Image transformer. Supports Canny, HED, Depth, Pose, MLSD, Scribble, Gray and inpainting; recommended\ncontrol_context_scale 0.70-0.95.\n\nInstantX's ControlNet-Union is a five-block copy of the transformer (controlnet_x_embedder, transformer_blocks,\ncontrolnet_blocks) whose block outputs are added to the base image stream. Supports Canny, Soft Edge, Depth and\nPose; recommended control_context_scale 0.80-1.00 on the original Qwen Image it was trained on, about 1.5-2.0 on\nQwen Image 2512. It takes no inpainting condition." }, "ControlNet_Checkpoint_SD1_Config": { "properties": { @@ -96297,7 +96305,7 @@ "type": "object" }, "QwenImageControlField": { - "description": "Qwen Image Fun-ControlNet conditioning: a control image, an inpaint image with its mask, or both.", + "description": "Qwen Image ControlNet conditioning: a control image, an inpaint image with its mask, or both (the InstantX\nControlNet takes the control image alone).", "properties": { "image_name": { "anyOf": [ @@ -96344,7 +96352,7 @@ }, "control_context_scale": { "default": 0.85, - "description": "Strength of the control signal. Recommended range: 0.70-0.95.", + "description": "Strength of the control signal. Recommended range: 0.70-0.95 for the Fun-ControlNet-Union; for the InstantX ControlNet-Union 0.80-1.00 on the original Qwen Image, about 1.5-2.0 on Qwen Image 2512.", "maximum": 2.0, "minimum": 0.0, "title": "Control Context Scale", @@ -96389,7 +96397,7 @@ "category": "conditioning", "class": "invocation", "classification": "prototype", - "description": "Configure the Qwen Image Fun-ControlNet-Union for spatial control, inpainting, or both.\n\nTakes a preprocessed control image (Canny, HED, depth, pose, MLSD, ...) and/or an image to inpaint with its mask\n(white is regenerated), plus the Qwen Image ControlNet model. Recommended control scale: 0.70-0.95.", + "description": "Configure a Qwen Image ControlNet for spatial control, inpainting, or both.\n\nTakes a preprocessed control image (Canny, HED, depth, pose, MLSD, ...) and/or an image to inpaint with its mask\n(white is regenerated), plus the Qwen Image ControlNet model. The Fun-ControlNet-Union takes either or both\n(recommended scale 0.70-0.95); the InstantX ControlNet-Union takes the control image only (0.80-1.00 on the\noriginal Qwen Image, about 1.5-2.0 on Qwen Image 2512).", "node_pack": "invokeai", "properties": { "id": { @@ -96484,7 +96492,7 @@ }, "control_context_scale": { "default": 0.85, - "description": "Strength of the control signal. Recommended range: 0.70-0.95.", + "description": "Strength of the control signal. Recommended range: 0.70-0.95 for the Fun-ControlNet-Union; for the InstantX ControlNet-Union 0.80-1.00 on the original Qwen Image, about 1.5-2.0 on Qwen Image 2512.", "field_kind": "input", "input": "any", "maximum": 2.0, diff --git a/invokeai/frontend/api/schema.ts b/invokeai/frontend/api/schema.ts index 3f58dd1f220..632a09f456d 100644 --- a/invokeai/frontend/api/schema.ts +++ b/invokeai/frontend/api/schema.ts @@ -9801,14 +9801,16 @@ export type components = { }; /** * ControlNet_Checkpoint_QwenImage_Config - * @description Model config for Qwen-Image Fun-ControlNet adapter models (Safetensors checkpoint). + * @description Model config for Qwen-Image ControlNet models (Safetensors checkpoint), in either of two designs. * - * Qwen-Image Fun-ControlNets are standalone adapters containing only the control branch - * (control_img_in, control_blocks) that extends the base Qwen-Image transformer with spatial - * conditioning capabilities. + * alibaba-pai's Fun-ControlNet-Union is a control branch (control_img_in, control_blocks) hooked into the base + * Qwen-Image transformer. Supports Canny, HED, Depth, Pose, MLSD, Scribble, Gray and inpainting; recommended + * control_context_scale 0.70-0.95. * - * Supports: Canny, HED, Depth, Pose, MLSD, Scribble, Gray, inpainting. - * Recommended control_context_scale: 0.70-0.95. + * InstantX's ControlNet-Union is a five-block copy of the transformer (controlnet_x_embedder, transformer_blocks, + * controlnet_blocks) whose block outputs are added to the base image stream. Supports Canny, Soft Edge, Depth and + * Pose; recommended control_context_scale 0.80-1.00 on the original Qwen Image it was trained on, about 1.5-2.0 on + * Qwen Image 2512. It takes no inpainting condition. */ ControlNet_Checkpoint_QwenImage_Config: { /** @@ -9887,6 +9889,13 @@ export type components = { */ base: "qwen-image"; default_settings: components["schemas"]["ControlAdapterDefaultSettings"] | null; + /** + * Control Architecture + * @description Which Qwen-Image ControlNet design the file holds: 'fun_union' (alibaba-pai Fun-ControlNet-Union, control and inpainting) or 'instantx_union' (InstantX ControlNet-Union, control only). Records written before the field existed are Fun-ControlNets. + * @default fun_union + * @enum {string} + */ + control_architecture: "fun_union" | "instantx_union"; }; /** ControlNet_Checkpoint_SD1_Config */ ControlNet_Checkpoint_SD1_Config: { @@ -41613,7 +41622,8 @@ export type components = { }; /** * QwenImageControlField - * @description Qwen Image Fun-ControlNet conditioning: a control image, an inpaint image with its mask, or both. + * @description Qwen Image ControlNet conditioning: a control image, an inpaint image with its mask, or both (the InstantX + * ControlNet takes the control image alone). */ QwenImageControlField: { /** @@ -41638,7 +41648,7 @@ export type components = { control_model: components["schemas"]["ModelIdentifierField"]; /** * Control Context Scale - * @description Strength of the control signal. Recommended range: 0.70-0.95. + * @description Strength of the control signal. Recommended range: 0.70-0.95 for the Fun-ControlNet-Union; for the InstantX ControlNet-Union 0.80-1.00 on the original Qwen Image, about 1.5-2.0 on Qwen Image 2512. * @default 0.85 */ control_context_scale?: number; @@ -41669,10 +41679,12 @@ export type components = { }; /** * Qwen Image ControlNet - * @description Configure the Qwen Image Fun-ControlNet-Union for spatial control, inpainting, or both. + * @description Configure a Qwen Image ControlNet for spatial control, inpainting, or both. * * Takes a preprocessed control image (Canny, HED, depth, pose, MLSD, ...) and/or an image to inpaint with its mask - * (white is regenerated), plus the Qwen Image ControlNet model. Recommended control scale: 0.70-0.95. + * (white is regenerated), plus the Qwen Image ControlNet model. The Fun-ControlNet-Union takes either or both + * (recommended scale 0.70-0.95); the InstantX ControlNet-Union takes the control image only (0.80-1.00 on the + * original Qwen Image, about 1.5-2.0 on Qwen Image 2512). */ QwenImageControlInvocation: { /** @@ -41715,7 +41727,7 @@ export type components = { control_model?: components["schemas"]["ModelIdentifierField"] | null; /** * Control Scale - * @description Strength of the control signal. Recommended range: 0.70-0.95. + * @description Strength of the control signal. Recommended range: 0.70-0.95 for the Fun-ControlNet-Union; for the InstantX ControlNet-Union 0.80-1.00 on the original Qwen Image, about 1.5-2.0 on Qwen Image 2512. * @default 0.85 */ control_context_scale?: number; diff --git a/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json b/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json index 86524b00da9..10dc4969db2 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json +++ b/invokeai/frontend/webv2/src/features/generation/core/__snapshots__/qwenImageControlCanvasGraphs.json @@ -410,6 +410,392 @@ } } }, + "inpaint_instantx_control_layer": { + "edges": [ + { + "destination": { + "field": "vae", + "node_id": "canvas_l2i" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "latents", + "node_id": "canvas_l2i" + }, + "source": { + "field": "latents", + "node_id": "denoise_latents" + } + }, + { + "destination": { + "field": "transformer", + "node_id": "denoise_latents" + }, + "source": { + "field": "transformer", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "vae", + "node_id": "denoise_latents" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "pos_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "pos_cond" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "positive_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "pos_cond" + } + }, + { + "destination": { + "field": "qwen_vl_encoder", + "node_id": "neg_cond" + }, + "source": { + "field": "qwen_vl_encoder", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "prompt", + "node_id": "neg_cond" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "negative_conditioning", + "node_id": "denoise_latents" + }, + "source": { + "field": "conditioning", + "node_id": "neg_cond" + } + }, + { + "destination": { + "field": "seed", + "node_id": "denoise_latents" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "seed", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "seed" + } + }, + { + "destination": { + "field": "positive_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "positive_prompt" + } + }, + { + "destination": { + "field": "negative_prompt", + "node_id": "core_metadata_0_i" + }, + "source": { + "field": "value", + "node_id": "negative_prompt" + } + }, + { + "destination": { + "field": "metadata", + "node_id": "canvas_output" + }, + "source": { + "field": "metadata", + "node_id": "core_metadata_0_i" + } + }, + { + "destination": { + "field": "vae", + "node_id": "canvas_i2l" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "latents", + "node_id": "denoise_latents" + }, + "source": { + "field": "latents", + "node_id": "canvas_i2l" + } + }, + { + "destination": { + "field": "vae", + "node_id": "create_gradient_mask" + }, + "source": { + "field": "vae", + "node_id": "model_loader" + } + }, + { + "destination": { + "field": "denoise_mask", + "node_id": "denoise_latents" + }, + "source": { + "field": "denoise_mask", + "node_id": "create_gradient_mask" + } + }, + { + "destination": { + "field": "mask", + "node_id": "expand_mask" + }, + "source": { + "field": "expanded_mask_area", + "node_id": "create_gradient_mask" + } + }, + { + "destination": { + "field": "layer_upper", + "node_id": "canvas_output" + }, + "source": { + "field": "image", + "node_id": "canvas_l2i" + } + }, + { + "destination": { + "field": "mask", + "node_id": "canvas_output" + }, + "source": { + "field": "image", + "node_id": "expand_mask" + } + }, + { + "destination": { + "field": "control", + "node_id": "denoise_latents" + }, + "source": { + "field": "control", + "node_id": "qwen_image_control_q-control" + } + } + ], + "id": "qwen_image_control_canvas_inpaint_instantx", + "nodes": { + "negative_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "negative_prompt", + "type": "string" + }, + "positive_prompt": { + "is_intermediate": true, + "use_cache": true, + "id": "positive_prompt", + "type": "string" + }, + "seed": { + "is_intermediate": true, + "use_cache": true, + "id": "seed", + "type": "integer" + }, + "model_loader": { + "is_intermediate": true, + "use_cache": true, + "id": "model_loader", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "type": "qwen_image_model_loader" + }, + "pos_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "pos_cond", + "type": "qwen_image_text_encoder" + }, + "neg_cond": { + "is_intermediate": true, + "use_cache": true, + "id": "neg_cond", + "type": "qwen_image_text_encoder" + }, + "denoise_latents": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "height": 1024, + "id": "denoise_latents", + "steps": 40, + "type": "qwen_image_denoise", + "width": 768, + "denoising_end": 1, + "denoising_start": 0.4 + }, + "core_metadata_0_i": { + "is_intermediate": true, + "use_cache": true, + "cfg_scale": 4, + "cfg_rescale_multiplier": 0, + "generation_mode": "qwen_image_inpaint", + "height": 1024, + "id": "core_metadata_0_i", + "model": { + "base": "qwen-image", + "format": "diffusers", + "key": "qwen-model", + "name": "Qwen Image", + "type": "main", + "hash": "blake3:qwen" + }, + "rand_device": "cpu", + "seamless_x": false, + "seamless_y": false, + "steps": 40, + "type": "core_metadata", + "width": 768, + "qwen_image_quantization": "none", + "qwen_image_shift": "auto", + "clip_skip": 0, + "strength": 0.6 + }, + "canvas_i2l": { + "is_intermediate": true, + "use_cache": true, + "id": "canvas_i2l", + "type": "qwen_image_i2l", + "image": { + "image_name": "canvas-composite.png" + } + }, + "create_gradient_mask": { + "is_intermediate": true, + "use_cache": true, + "coherence_mode": "Gaussian Blur", + "edge_radius": 16, + "fp32": false, + "id": "create_gradient_mask", + "image": { + "image_name": "canvas-composite.png" + }, + "minimum_denoise": 0, + "type": "create_gradient_mask", + "mask": { + "image_name": "canvas-mask.png" + } + }, + "expand_mask": { + "is_intermediate": true, + "use_cache": true, + "fade_size_px": 16, + "id": "expand_mask", + "type": "expand_mask_with_fade" + }, + "canvas_l2i": { + "is_intermediate": true, + "use_cache": false, + "id": "canvas_l2i", + "type": "qwen_image_l2i" + }, + "canvas_output": { + "is_intermediate": true, + "use_cache": false, + "layer_base": { + "image_name": "canvas-composite.png" + }, + "type": "invokeai_img_blend", + "id": "canvas_output" + }, + "qwen_image_control_q-control": { + "is_intermediate": true, + "use_cache": true, + "begin_step_percent": 0, + "control_context_scale": 0.85, + "control_model": { + "base": "qwen-image", + "key": "qwen-instantx", + "name": "Qwen Image InstantX ControlNet Union", + "type": "controlnet", + "hash": "blake3:instantx" + }, + "end_step_percent": 1, + "id": "qwen_image_control_q-control", + "image": { + "image_name": "q-control.png" + }, + "type": "qwen_image_control" + } + } + }, "outpaint_control_layer": { "edges": [ { diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts index 82caeb025d7..a810bb665a0 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.test.ts @@ -442,6 +442,38 @@ describe('addControlLayers — Qwen-Image control', () => { ]); }); + it('hands an InstantX union the control image alone, as the canvas inpaints', () => { + const graph = run({ + base: 'qwen-image', + inpaint, + layers: [qwenLayer('Q1', { modelControlArchitecture: 'instantx_union' })], + }); + + expect(graph.nodes.qwen_image_control_Q1).toEqual({ + begin_step_percent: 0, + control_context_scale: 0.85, + control_model: union, + end_step_percent: 1, + id: 'qwen_image_control_Q1', + image: { image_name: 'Q1.png' }, + is_intermediate: true, + type: 'qwen_image_control', + use_cache: true, + }); + expect(Object.keys(graph.nodes)).toEqual(['denoise_latents', 'qwen_image_control_Q1']); + expect(graph.edges.map((edge) => edge.destination)).toEqual([{ field: 'control', node_id: 'denoise_latents' }]); + }); + + it.each(['fun_union', null, undefined] as const)( + 'hands a Fun union (record says %s) the inpainted region as well', + (modelControlArchitecture) => { + const graph = run({ base: 'qwen-image', inpaint, layers: [qwenLayer('Q1', { modelControlArchitecture })] }); + + expect(graph.nodes.qwen_image_control_Q1).toMatchObject({ inpaint_image: { image_name: 'composite.png' } }); + expect(edgesTo(graph, 'qwen_image_control_Q1', 'inpaint_mask')).toHaveLength(1); + } + ); + it('leaves the inpaint inputs to the kinds that condition on the region', () => { const graph = run({ base: 'z-image', diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts index 9ed4549d6dd..b3c006727c0 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/addControlLayers.ts @@ -2,6 +2,7 @@ import type { SupportedGenerateBase } from '@features/generation/core/baseGenerationPolicies'; import type { BackendGraphContract, BackendInvocationContract } from '@features/generation/core/contracts'; +import type { ModelConfig } from '@features/models'; import { addEdge, addNode } from '@features/generation/core/graphBuilder'; @@ -40,6 +41,11 @@ export interface ControlLayerGraphInput { controlMode: 'balanced' | 'more_prompt' | 'more_control' | 'unbalanced' | null; /** The resolved model's `cond_in_channels`; required to validate an Anima ControlNet-LLLite layer. */ modelCondInChannels?: number | null; + /** + * The resolved model's `control_architecture` (Qwen-Image ControlNets). `instantx_union` takes the control image + * only; a Fun union, or a record written before the field existed, also takes the inpainted region. + */ + modelControlArchitecture?: ModelConfig['control_architecture'] | null; } /** Kind support is separate from control-mode/model compatibility. */ @@ -80,8 +86,8 @@ export interface AddControlLayersOptions { /** The valid, resolved control layers to graft (in document order). */ layers: readonly ControlLayerGraphInput[]; /** - * Present when the canvas compiles in inpaint or outpaint mode. The Qwen-Image control node also conditions on - * the inpainted region and takes them; the other kinds ignore them. + * Present when the canvas compiles in inpaint or outpaint mode. The Qwen-Image control node of a Fun union also + * conditions on the inpainted region and takes them; the other kinds and models ignore them. */ inpaint?: CanvasInpaintSources; } @@ -203,9 +209,10 @@ export const addControlLayers = (graph: BackendGraphContract, options: AddContro image: { image_name: layer.imageName }, type: 'qwen_image_control', }); - if (inpaint) { - // The union's inpainting condition. The canvas mask is white = keep and the node wants white = regenerate, - // so `img_lerp` 255 → 0 inverts it first, as the Anima inpaint adapter does. + if (inpaint && layer.modelControlArchitecture !== 'instantx_union') { + // The Fun union's inpainting condition; InstantX's union has no input for one. The canvas mask is white = + // keep and the node wants white = regenerate, so `img_lerp` 255 → 0 inverts it first, as the Anima inpaint + // adapter does. const invertMask = addNode(graph, { id: `qwen_image_control_mask_${layer.id}`, max: 0, diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts index e18ab8f1d50..fe51dabfcde 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/compileCanvasGraph.test.ts @@ -940,6 +940,16 @@ describe('compileCanvasGraph — Qwen-Image ControlNet (integration)', () => { model: { base: 'qwen-image', key: 'qwen-union', name: 'Qwen Image ControlNet Union', type: 'controlnet' }, weight: 0.85, }; + const instantxLayer: ControlLayerGraphInput = { + ...layer, + model: { + base: 'qwen-image', + key: 'qwen-instantx', + name: 'Qwen Image InstantX ControlNet Union', + type: 'controlnet', + }, + modelControlArchitecture: 'instantx_union', + }; const CONTROL = 'qwen_image_control_q-control'; const MASK = 'qwen_image_control_mask_q-control'; const edgesInto = (graph: BackendGraphContract, nodeId: string) => @@ -1034,6 +1044,21 @@ describe('compileCanvasGraph — Qwen-Image ControlNet (integration)', () => { expect(getEdge(scaled, CONTROL, 'inpaint_image')?.source.node_id).toBe('infill'); }); + it.each(['inpaint', 'outpaint'] as const)('%s: an InstantX union reads the control image alone', (mode) => { + const { backendGraph } = compile(qwenImageModel, mode, { controlLayers: [instantxLayer] }); + + expect(backendGraph.nodes[CONTROL]).toMatchObject({ + control_model: instantxLayer.model, + image: { image_name: 'q-control.png' }, + }); + expect(backendGraph.nodes[CONTROL]).not.toHaveProperty('inpaint_image'); + expect(edgesInto(backendGraph, CONTROL)).toEqual([]); + expect(backendGraph.nodes[MASK]).toBeUndefined(); + // The region is still inpainted: the denoise keeps its mask. + expect(getEdge(backendGraph, 'denoise_latents', 'denoise_mask')?.source.node_id).toBe('create_gradient_mask'); + expect(getEdge(backendGraph, 'denoise_latents', 'control')?.source).toEqual({ field: 'control', node_id: CONTROL }); + }); + it('rejects the control on a Qwen Image Edit model, as the denoise does', () => { expect(() => compile({ ...qwenImageModel, variant: 'edit' }, 'inpaint', { controlLayers: [layer] })).toThrow( /qwen_image_edit_control/ @@ -1055,15 +1080,19 @@ describe('compileCanvasGraph — Qwen-Image ControlNet (integration)', () => { const hashed = (config: T, hash: string): T => ({ ...config, hash }); const model = hashed(qwenImageModel, 'blake3:qwen'); const controlLayers = [{ ...layer, model: hashed(layer.model, 'blake3:union') }]; + const instantxLayers = [{ ...instantxLayer, model: hashed(instantxLayer.model, 'blake3:instantx') }]; let txt2img: BackendGraphContract; let inpaint: BackendGraphContract; let outpaint: BackendGraphContract; + let instantxInpaint: BackendGraphContract; try { txt2img = compile(model, 'txt2img', { controlLayers }).backendGraph; // Without Scale Before Processing the control reads the canvas uploads as fixed image fields. inpaint = compile(model, 'inpaint', { controlLayers }).backendGraph; // The infilled image and the combined mask reach the control through edges. outpaint = compile(model, 'outpaint', { controlLayers, maskImageName: 'canvas-mask.png' }).backendGraph; + // An InstantX union inpaints with the control image alone. + instantxInpaint = compile(model, 'inpaint', { controlLayers: instantxLayers }).backendGraph; } finally { clock.mockRestore(); random.mockRestore(); @@ -1072,6 +1101,7 @@ describe('compileCanvasGraph — Qwen-Image ControlNet (integration)', () => { _comment: 'Generated by compileCanvasGraph.test.ts; regenerate with `vitest -u`. Consumed by tests/app/invocations/test_frontend_qwen_image_control_graphs.py, which validates the graphs against the backend invocations.', inpaint_control_layer: { ...inpaint, id: 'qwen_image_control_canvas_inpaint' }, + inpaint_instantx_control_layer: { ...instantxInpaint, id: 'qwen_image_control_canvas_inpaint_instantx' }, outpaint_control_layer: { ...outpaint, id: 'qwen_image_control_canvas_outpaint' }, txt2img_control_layer: { ...txt2img, id: 'qwen_image_control_canvas_txt2img' }, }; diff --git a/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts b/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts index 90088e0761e..f3a9abf6b08 100644 --- a/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts +++ b/invokeai/frontend/webv2/src/features/generation/core/canvas/controlValidation.ts @@ -163,7 +163,7 @@ export const getControlValidationReason = (params: { return 'flux_fill_control_lora'; } if (kind === 'qwen_image_control' && mainBase === 'qwen-image' && mainVariant === 'edit') { - // The Fun-ControlNet branch was trained beside the generation transformer; `qwen_image_denoise` refuses it on + // Both ControlNet designs were trained beside the generation transformer; `qwen_image_denoise` refuses either on // an Edit transformer. return 'qwen_image_edit_control'; } diff --git a/invokeai/frontend/webv2/src/features/models/core/types.ts b/invokeai/frontend/webv2/src/features/models/core/types.ts index de39d5ea2d9..19ac082125b 100644 --- a/invokeai/frontend/webv2/src/features/models/core/types.ts +++ b/invokeai/frontend/webv2/src/features/models/core/types.ts @@ -152,6 +152,8 @@ export interface ModelConfig { image_encoder_model_id?: string; /** Anima ControlNet-LLLite: 3 = control image, 4 = inpainting; null when installed before it was recorded. */ cond_in_channels?: number | null; + /** Qwen-Image ControlNets: `fun_union` also conditions on an inpainted region, `instantx_union` does not. */ + control_architecture?: 'fun_union' | 'instantx_union'; /** External API models. */ provider_id?: string; provider_model_id?: string; diff --git a/invokeai/frontend/webv2/src/workbench/controlAdapters.ts b/invokeai/frontend/webv2/src/workbench/controlAdapters.ts index 8963492f277..02509591f44 100644 --- a/invokeai/frontend/webv2/src/workbench/controlAdapters.ts +++ b/invokeai/frontend/webv2/src/workbench/controlAdapters.ts @@ -26,7 +26,7 @@ export const CONTROL_ADAPTER_DEFAULTS: Readonly< model: null, weight: 0.75, }, - // The Fun-ControlNet-Union's recommended 0.70–0.95 context scale, centred. + // Inside both unions' recommended context scales: Fun 0.70–0.95, InstantX 0.80–1.00. qwen_image_control: { beginEndStepPct: [0, 1], controlMode: null, diff --git a/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts b/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts index e311bf6ed42..ef39719bb8f 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts +++ b/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.test.ts @@ -1072,6 +1072,34 @@ describe('runCanvasInvocation', () => { }); }); + it('hands an InstantX union, as its record says it is, the control image alone when the canvas inpaints', async () => { + const instantx = { + ...union, + control_architecture: 'instantx_union' as const, + hash: 'qwen-instantx-hash', + key: 'qwen-instantx', + name: 'Qwen Image InstantX ControlNet Union', + }; + const harness = makeHarness({ + document: docWithLayers([ + rasterLayer('base'), + qwenLayer('q-layer', { model: instantx.key }), + inpaintMaskLayer('mask'), + ]), + model: qwenImage, + models: [union, instantx], + }); + + await runCanvasInvocation(harness.deps); + + expect(harness.notices()).toHaveLength(0); + const nodes = harness.submittedGraphs()[0]!.graph.backendGraph!.nodes; + expect(nodes['qwen_image_control_q-layer']).toMatchObject({ control_model: { key: 'qwen-instantx' } }); + expect(nodes['qwen_image_control_q-layer']).not.toHaveProperty('inpaint_image'); + expect(nodes['qwen_image_control_mask_q-layer']).toBeUndefined(); + expect(nodes.create_gradient_mask).toBeDefined(); + }); + it('blocks a second enabled nonempty control', async () => { const harness = makeHarness({ document: docWithLayers([qwenLayer('first'), qwenLayer('second')]), diff --git a/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.ts b/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.ts index ae525b4b8e3..e5ce0cb74d5 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.ts +++ b/invokeai/frontend/webv2/src/workbench/widgets/canvas/invoke/prepareCanvasInvocation.ts @@ -167,6 +167,7 @@ const createControlLayerCollector = ( ...(typeof resolved.hash === 'string' ? { hash: resolved.hash } : {}), }, modelCondInChannels: resolved.cond_in_channels, + modelControlArchitecture: resolved.control_architecture, weight: adapter.weight, }); return true; diff --git a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx index 6606914b7c1..c32ccd849b1 100644 --- a/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx +++ b/invokeai/frontend/webv2/src/workbench/widgets/layers/ControlLayerSettings.browser.test.tsx @@ -432,18 +432,25 @@ describe('ControlLayerSettings on a Qwen Image main model', () => { const QWEN_EDIT_MAIN = { ...QWEN_MAIN, key: 'qwen-edit', name: 'Qwen Image Edit 2511', variant: 'edit' }; const QWEN_MODELS = [ { base: 'qwen-image', key: 'qwen-union', name: 'Qwen Image ControlNet Union', type: 'controlnet' }, + { + base: 'qwen-image', + control_architecture: 'instantx_union', + key: 'qwen-instantx', + name: 'Qwen Image InstantX ControlNet Union', + type: 'controlnet', + }, { base: 'z-image', key: 'z-union', name: 'Z-Image ControlNet Union', type: 'controlnet' }, ]; /** A layer as the Layers panel creates it under a Qwen Image main model. */ const qwenLayer = (id: string) => createControlLayer(id, id, 'qwen-image', 'qwen-union'); - it('offers the Qwen Image ControlNet kind and its models, and accepts one without a warning', async () => { + it('offers the Qwen Image ControlNet kind and both of its designs, and accepts one without a warning', async () => { await renderWith(QWEN_MAIN, QWEN_MODELS, qwenLayer('control-1')); expect(offersKind('qwen_image_control')).toBe(true); expect(offersKind('controlnet')).toBe(false); expect(offersKind('z_image_control')).toBe(false); - expect(offeredModels()).toEqual(['qwen-union']); + expect(offeredModels()).toEqual(['qwen-union', 'qwen-instantx']); expect(host!.textContent).toContain('Qwen Image ControlNet Union'); expect(textOf('alert')).toBe(''); }); diff --git a/tests/app/invocations/test_frontend_qwen_image_control_graphs.py b/tests/app/invocations/test_frontend_qwen_image_control_graphs.py index 214bd29f208..31064cd5e25 100644 --- a/tests/app/invocations/test_frontend_qwen_image_control_graphs.py +++ b/tests/app/invocations/test_frontend_qwen_image_control_graphs.py @@ -2,8 +2,9 @@ `qwenImageControlCanvasGraphs.json` is written by webv2's `compileCanvasGraph.test.ts` (regenerate with `vitest -u`) from the real canvas compiler: a text-to-image submission with one control layer, an inpainting -submission where that layer also hands the control the canvas composite and the inverted canvas mask, and an -outpainting submission where it hands over the infilled image and the combined mask through edges. This module +submission where that layer also hands the control the canvas composite and the inverted canvas mask, an +outpainting submission where it hands over the infilled image and the combined mask through edges, and an inpainting +submission whose layer holds an InstantX union, which gets the control image alone. This module checks more than names: pydantic validates every node against its invocation (bounds such as `qwen_image_control.control_context_scale` in [0, 2] included), `Graph.validate_self` checks every edge type into `qwen_image_denoise.control` and `.vae`, the control node's own `invoke` runs on the fields it would receive, and @@ -80,7 +81,12 @@ def _control_field(graph: Graph, node: QwenImageControlInvocation) -> QwenImageC def test_the_fixtures_cover_every_canvas_mode_with_one_control_layer() -> None: - assert sorted(GRAPHS) == ["inpaint_control_layer", "outpaint_control_layer", "txt2img_control_layer"] + assert sorted(GRAPHS) == [ + "inpaint_control_layer", + "inpaint_instantx_control_layer", + "outpaint_control_layer", + "txt2img_control_layer", + ] for name, raw in GRAPHS.items(): types = [node["type"] for node in raw["nodes"].values()] assert types.count("qwen_image_control") == 1, name @@ -183,6 +189,26 @@ def test_outpainting_adds_the_infilled_image_and_the_inverted_combined_mask() -> assert field.inpaint_image_name is not None and field.inpaint_mask_name is not None +def test_an_instantx_inpaint_sends_the_control_image_alone_and_keeps_the_denoise_mask() -> None: + """The InstantX union has no inpainting condition and the denoise refuses one, so the canvas leaves the inpaint + inputs off its node; the region is still regenerated through the denoise mask.""" + graph = Graph.model_validate(GRAPHS["inpaint_instantx_control_layer"]) + graph.validate_self() + control = _control_node(graph) + + assert control.control_model.key == "qwen-instantx" + assert control.image is not None and control.image.image_name == "q-control.png" + assert control.inpaint_image is None and control.inpaint_mask is None + assert _inputs(graph, control.id) == {} + assert not any(isinstance(node, ImageLerpInvocation) for node in graph.nodes.values()) + gradient_mask = graph.nodes[_inputs(graph, _denoise_node(graph).id)["denoise_mask"].node_id] + assert isinstance(gradient_mask, CreateGradientMaskInvocation) + assert gradient_mask.mask.image_name == "canvas-mask.png" + field = _control_field(graph, control) + assert field.image_name == "q-control.png" + assert field.inpaint_image_name is None and field.inpaint_mask_name is None + + def test_the_control_node_refuses_the_half_pair_the_frontend_never_sends() -> None: """The frontend sends the inpaint image and mask together or not at all; pin the node constraint it mirrors.""" graph = Graph.model_validate(GRAPHS["inpaint_control_layer"]) @@ -198,6 +224,7 @@ def test_the_control_node_refuses_the_half_pair_the_frontend_never_sends() -> No [ ("txt2img_control_layer", "qwen_image_txt2img"), ("inpaint_control_layer", "qwen_image_inpaint"), + ("inpaint_instantx_control_layer", "qwen_image_inpaint"), ("outpaint_control_layer", "qwen_image_outpaint"), ], ) diff --git a/tests/app/invocations/test_qwen_image_control.py b/tests/app/invocations/test_qwen_image_control.py index d711745d87c..3b745994ea5 100644 --- a/tests/app/invocations/test_qwen_image_control.py +++ b/tests/app/invocations/test_qwen_image_control.py @@ -3,9 +3,10 @@ reservation inside the exit stack, gates it per step, and builds the packed control context from the field's images the way it packs its latents. -The denoise runs its transformer in bfloat16, which the CPU test fleet cannot matmul, so every run here stops at the -transformer's lock or at the LoRA patcher, or runs the loop with the transformer's forward stood in. The forward with -the hooks is covered in `tests/backend/fun_controlnet`. +The denoise runs its transformer in bfloat16, which the CPU test fleet cannot matmul, so the Fun runs here stop at the +transformer's lock or at the LoRA patcher, or run the loop with the transformer's forward stood in; the forward with +the hooks is covered in `tests/backend/fun_controlnet`. The InstantX runs go through the real tiny transformer and +ControlNet, each widening what the node feeds it to float32 (`_Float32Compute`). """ from contextlib import contextmanager, nullcontext @@ -15,6 +16,7 @@ import pytest import torch from diffusers.models.autoencoders.autoencoder_kl_qwenimage import AutoencoderKLQwenImage +from diffusers.models.controlnets.controlnet_qwenimage import QwenImageControlNetModel from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformer2DModel from PIL import Image from pydantic import ValidationError @@ -314,12 +316,13 @@ def test_with_control_the_lock_reserves_the_hints_too_and_the_images_are_encoded with pytest.raises(_Stop): _denoise()._run_diffusion(context) - expected = QwenImageDenoiseInvocation._estimate_working_memory( - image_seq_len=16, - text_seq_len=TEXT_TOKENS, - element_size=torch.bfloat16.itemsize, - num_control_blocks=len(CONTROL_LAYERS), - control_hidden_size=HIDDEN, + expected = ( + QwenImageDenoiseInvocation._estimate_working_memory( + image_seq_len=16, + text_seq_len=TEXT_TOKENS, + element_size=torch.bfloat16.itemsize, + ) + + (len(CONTROL_LAYERS) + 4) * 16 * HIDDEN * torch.bfloat16.itemsize ) assert transformer_info.model_on_device.call_args.kwargs["working_mem_bytes"] == expected # The control image and the masked inpaint image went through the VAE before the transformer was locked. @@ -463,7 +466,7 @@ def recording(**kwargs): monkeypatch.setattr(QwenImageImageToLatentsInvocation, "vae_encode", staticmethod(recording)) _denoise(control=_control_field(tiled=tiled, tile_size=tile_size))._build_control_context( - context, LATENT_SIDE, LATENT_SIDE + context, _tiny_branch(), LATENT_SIDE, LATENT_SIDE ) # Once for the control image, once for the masked inpaint image, both with the field's tiling. @@ -482,7 +485,7 @@ def test_the_control_context_is_the_encoded_images_packed_like_the_latents(tmp_p vae_info = _loaded(vae, _yielding(vae)) context = _context(tmp_path, vae_info=vae_info) - packed = _denoise()._build_control_context(context, LATENT_SIDE, LATENT_SIDE) + packed = _denoise()._build_control_context(context, _tiny_branch(), LATENT_SIDE, LATENT_SIDE) assert packed.shape == (1, (LATENT_SIDE // 2) ** 2, 33 * 4) # Channel-major within a token: feature c * 4 + dy * 2 + dx of token (i, j) is channel c at (2i + dy, 2j + dx). @@ -502,3 +505,258 @@ def encode(pixels: torch.Tensor) -> torch.Tensor: masked = _as_denoise_input(_inpaint_image(), "RGB") masked[..., : SIDE // 2, : SIDE // 2] = 0.0 assert torch.equal(context_4d[:, 17:], encode(masked)) + + +# --- the InstantX ControlNet --- + +INSTANTX_BLOCKS = 2 +INSTANTX_SCALE = 0.9 + + +def _widened(value): + if isinstance(value, torch.Tensor): + return value.float() if value.is_floating_point() else value + if isinstance(value, (list, tuple)): + return type(value)(_widened(item) for item in value) + return value + + +class _Float32Compute: + """Runs the real forward in float32 on what the node feeds it in bfloat16, and hands the result back in the + dtype it was fed: the bfloat16 GEMM the CPU fleet lacks, done wider. The direct restatement calls the same + models, so both sides see the same arithmetic.""" + + def forward(self, **kwargs): + dtype = kwargs["hidden_states"].dtype + output = super().forward(**{name: _widened(value) for name, value in kwargs.items()}) # type: ignore[misc] + return [tensor.to(dtype) for tensor in output] + + +class _InstantXTransformer(_Float32Compute, QwenImageTransformer2DModel): + """The tiny transformer, recording every forward the node makes: its arguments and its output.""" + + def forward(self, **kwargs): + output = super().forward(**kwargs) + self.calls.append(SimpleNamespace(kwargs=kwargs, output=output[0])) + return (output[0],) + + +class _InstantXControlNet(_Float32Compute, QwenImageControlNetModel): + """The tiny ControlNet, counting its forwards.""" + + def forward(self, **kwargs): + self.calls += 1 + return super().forward(**kwargs) + + +def _randomized(model: torch.nn.Module, seed: int) -> torch.nn.Module: + """Every parameter from N(0, 0.1): diffusers zero-initialises `controlnet_blocks` and `controlnet_x_embedder`, + which would make every residual zero and every comparison here vacuous, and leaves the modulation gates near + zero.""" + torch.manual_seed(seed) + for parameter in model.parameters(): + torch.nn.init.normal_(parameter, std=0.1) + return model.eval() + + +def _instantx_transformer() -> _InstantXTransformer: + model = _InstantXTransformer( + patch_size=2, + in_channels=64, + out_channels=16, + num_layers=4, + attention_head_dim=8, + num_attention_heads=2, + joint_attention_dim=8, + axes_dims_rope=(2, 4, 2), + ) + model.calls = [] + _randomized(model, seed=10) + return model + + +def _instantx_controlnet() -> _InstantXControlNet: + model = _InstantXControlNet( + patch_size=2, + in_channels=64, + out_channels=16, + num_layers=INSTANTX_BLOCKS, + attention_head_dim=8, + num_attention_heads=2, + joint_attention_dim=8, + axes_dims_rope=(2, 4, 2), + ) + model.calls = 0 + _randomized(model, seed=11) + return model + + +# Distinct prompts, the positive one padded, so a ControlNet fed the negative prompt or its mask would show. +_PROMPTS = { + "pos": (torch.randn(1, TEXT_TOKENS, 8, generator=torch.Generator().manual_seed(20)), [True, True, True, False]), + "neg": (torch.randn(1, TEXT_TOKENS, 8, generator=torch.Generator().manual_seed(21)), [True, True, True, True]), +} + + +def _prompt(name: str) -> tuple[torch.Tensor, torch.Tensor]: + """A prompt as the denoise holds it: embeddings in bfloat16, the mask as is.""" + embeds, mask = _PROMPTS[name] + return embeds.to(torch.bfloat16), torch.tensor([mask]) + + +def _instantx_context(tmp_path, transformer, controlnet, vae) -> MagicMock: + context = _context( + tmp_path, + _loaded(transformer, _yielding(transformer)), + _loaded(controlnet, _yielding(controlnet)), + _loaded(vae, _yielding(vae)), + ) + context.conditioning.load.side_effect = lambda name: ConditioningFieldData( + conditionings=[ + QwenImageConditioningInfo( + prompt_embeds=_PROMPTS[name][0], prompt_embeds_mask=torch.tensor([_PROMPTS[name][1]]) + ) + ] + ) + return context + + +def _instantx_field(**overrides) -> QwenImageControlField: + fields = {"inpaint_image_name": None, "inpaint_mask_name": None, "control_context_scale": INSTANTX_SCALE} + fields.update(overrides) + return _control_field(**fields) + + +def _expected_control_latents(vae) -> torch.Tensor: + """diffusers' pipeline: the control image at generation size in [-1, 1], encoded and normalised, packed 2x2 into + `(1, tokens, 64)` and cast to the prompt's dtype.""" + pixels = _as_denoise_input(_control_image(), "RGB") + latents = QwenImageImageToLatentsInvocation.vae_encode(_loaded(vae, _yielding(vae)), pixels).squeeze(2) + half = LATENT_SIDE // 2 + packed = latents.view(1, 16, half, 2, half, 2).permute(0, 2, 4, 1, 3, 5).reshape(1, half * half, 64) + return packed.to(torch.bfloat16) + + +@torch.no_grad() +def test_an_instantx_step_is_the_diffusers_controlnet_pipeline_step(tmp_path) -> None: + """Every step's two transformer forwards are what QwenImageControlNetPipeline computes from that step's + latents: the ControlNet once, on the positive prompt and its mask at `timestep / 1000`, and its scaled residuals + added in both guidance branches.""" + transformer, controlnet, vae = _instantx_transformer(), _instantx_controlnet(), _tiny_vae() + context = _instantx_context(tmp_path, transformer, controlnet, vae) + + _denoise(control=_instantx_field())._run_diffusion(context) + + calls = list(transformer.calls) + assert len(calls) == 4 and controlnet.calls == 2 + control_latents = _expected_control_latents(vae) + img_shapes = [[(1, LATENT_SIDE // 2, LATENT_SIDE // 2)]] + pos_embeds, pos_mask = _prompt("pos") + neg_embeds, neg_mask = _prompt("neg") + for positive, negative in (calls[0:2], calls[2:4]): + latents, timestep = positive.kwargs["hidden_states"], positive.kwargs["timestep"] + samples = controlnet( + hidden_states=latents, + controlnet_cond=control_latents, + conditioning_scale=INSTANTX_SCALE, + encoder_hidden_states=pos_embeds, + encoder_hidden_states_mask=pos_mask, + timestep=timestep, + img_shapes=img_shapes, + return_dict=False, + ) + shared = {"hidden_states": latents, "timestep": timestep, "img_shapes": img_shapes, "return_dict": False} + expected_positive = transformer( + encoder_hidden_states=pos_embeds, + encoder_hidden_states_mask=pos_mask, + controlnet_block_samples=samples, + **shared, + )[0] + expected_negative = transformer( + encoder_hidden_states=neg_embeds, + encoder_hidden_states_mask=neg_mask, + controlnet_block_samples=samples, + **shared, + )[0] + uncontrolled = transformer(encoder_hidden_states=pos_embeds, encoder_hidden_states_mask=pos_mask, **shared)[0] + + assert torch.equal(negative.kwargs["hidden_states"], latents) + assert torch.equal(positive.output, expected_positive) + assert torch.equal(negative.output, expected_negative) + # The residuals move the prediction, so the comparisons above can fail. + assert not torch.equal(positive.output, uncontrolled) + + +@torch.no_grad() +def test_an_instantx_control_at_scale_zero_generates_what_no_control_does(tmp_path) -> None: + vae = _tiny_vae() + + def generate(**overrides) -> torch.Tensor: + transformer, controlnet = _instantx_transformer(), _instantx_controlnet() + context = _instantx_context(tmp_path, transformer, controlnet, vae) + return _denoise(**overrides)._run_diffusion(context) + + uncontrolled = generate(control=None, vae=None) + + assert torch.equal(generate(control=_instantx_field(control_context_scale=0.0)), uncontrolled) + assert not torch.equal(generate(control=_instantx_field()), uncontrolled) + + +@torch.no_grad() +def test_an_instantx_control_outside_its_step_range_runs_no_controlnet(tmp_path) -> None: + """Four steps, the second half controlled: the ControlNet runs on the two steps inside the range only, and both + guidance forwards of a step take the same residuals or none.""" + transformer, controlnet, vae = _instantx_transformer(), _instantx_controlnet(), _tiny_vae() + context = _instantx_context(tmp_path, transformer, controlnet, vae) + + _denoise(steps=4, control=_instantx_field(begin_step_percent=0.5, end_step_percent=1.0))._run_diffusion(context) + + assert controlnet.calls == 2 + samples = [call.kwargs["controlnet_block_samples"] for call in transformer.calls] + assert samples[:4] == [None] * 4 + assert all(isinstance(residuals, list) and len(residuals) == INSTANTX_BLOCKS for residuals in samples[4:]) + assert samples[4] is samples[5] and samples[6] is samples[7] + + +@pytest.mark.parametrize("overrides", [{}, {"image_name": None}], ids=["control-and-inpaint", "inpaint-alone"]) +def test_an_instantx_control_refuses_inpaint_inputs(tmp_path, overrides) -> None: + transformer, controlnet, vae = _instantx_transformer(), _instantx_controlnet(), _tiny_vae() + context = _instantx_context(tmp_path, transformer, controlnet, vae) + vae_info = context.models.load(_model(ModelType.VAE)) + + with pytest.raises(ValueError, match="no inpainting condition"): + _denoise(control=_control_field(**overrides))._run_diffusion(context) + + # Refused before anything was encoded or run. + assert vae_info.model_on_device.call_count == 0 + assert transformer.calls == [] and controlnet.calls == 0 + + +def test_an_instantx_control_reserves_its_residuals_and_is_locked_with_the_same_reservation( + tmp_path, monkeypatch: pytest.MonkeyPatch +) -> None: + transformer, controlnet, vae = _instantx_transformer(), _instantx_controlnet(), _tiny_vae() + context = _instantx_context(tmp_path, transformer, controlnet, vae) + transformer_info = context.models.load(_model(ModelType.Main)) + control_info = context.models.load(_model(ModelType.ControlNet)) + hooks_at_patching: list[int] = [] + + def stop(**_kwargs): + hooks_at_patching.append(_hook_count(transformer)) + raise _Stop + + monkeypatch.setattr(LayerPatcher, "apply_smart_model_patches", stop) + + with pytest.raises(_Stop): + _denoise(control=_instantx_field())._run_diffusion(context) + + plain = QwenImageDenoiseInvocation._estimate_working_memory( + image_seq_len=16, text_seq_len=TEXT_TOKENS, element_size=torch.bfloat16.itemsize + ) + # The scaled residuals, one per block, alive through both guidance forwards: 16 tokens at the ControlNet's width. + residuals = INSTANTX_BLOCKS * 16 * HIDDEN * torch.bfloat16.itemsize + reserved = transformer_info.model_on_device.call_args.kwargs["working_mem_bytes"] + assert reserved == plain + residuals + assert control_info.model_on_device.call_args.kwargs["working_mem_bytes"] == reserved + # Nothing is hooked into the transformer: the ControlNet runs beside it. + assert hooks_at_patching == [0] diff --git a/tests/backend/flux/controlnet/test_state_dict_utils.py b/tests/backend/flux/controlnet/test_state_dict_utils.py index 2688dd3bebd..a47f328466c 100644 --- a/tests/backend/flux/controlnet/test_state_dict_utils.py +++ b/tests/backend/flux/controlnet/test_state_dict_utils.py @@ -13,6 +13,9 @@ ) from tests.backend.flux.controlnet.instantx_flux_controlnet_state_dict import instantx_config, instantx_sd_shapes from tests.backend.flux.controlnet.xlabs_flux_controlnet_state_dict import xlabs_sd_shapes +from tests.backend.model_manager.load.state_dicts.qwen_image_instantx_controlnet_keys import ( + state_dict_keys as qwen_image_instantx_keys, +) @pytest.mark.parametrize( @@ -33,6 +36,8 @@ def test_is_state_dict_xlabs_controlnet(sd_shapes: dict[str, list[int]], expecte [ (instantx_sd_shapes, True), (xlabs_sd_shapes, False), + # InstantX's Qwen-Image ControlNet: the same `controlnet_*` keys over Qwen-Image's own blocks. + (qwen_image_instantx_keys, False), (["foo"], False), ], ) diff --git a/tests/backend/model_manager/configs/test_qwen_image_controlnet_config.py b/tests/backend/model_manager/configs/test_qwen_image_controlnet_config.py new file mode 100644 index 00000000000..c02de7d17c4 --- /dev/null +++ b/tests/backend/model_manager/configs/test_qwen_image_controlnet_config.py @@ -0,0 +1,272 @@ +"""Identification of the two Qwen-Image ControlNet designs, through the config factory. + +alibaba-pai's Fun-ControlNet-Union is a VACE-style control branch: `control_img_in` projects 132 packed channels into +Qwen-Image's 3072-wide stream, and five `control_blocks` copy the dual-stream `QwenImageTransformerBlock` with +`before_proj`/`after_proj` taps. Its siblings reuse the naming -- the Qwen-Image-2.1 branch is single-stream at 4096 +wide, FLUX.2's keeps `control_transformer_blocks` at 6144. + +InstantX's ControlNet-Union is a five-block copy of the Qwen-Image transformer with `controlnet_x_embedder` and +`controlnet_blocks`: the key family of InstantX's FLUX ControlNets, and with `img_in`/`txt_in`/`txt_norm` the keys the +Qwen-Image main model probe reads. Both used to claim it, and the factory ranks main models first. + +Both are one config, the design recorded as `control_architecture`. Every case is a header written back without its +data: identification reads nothing else, and each config sees the real key names, shapes and dtypes. +""" + +from pathlib import Path + +import pytest +from pydantic import TypeAdapter + +from invokeai.backend.model_manager.configs.controlnet import ( + ControlNet_Checkpoint_FLUX_Config, + ControlNet_Checkpoint_QwenImage_Config, +) +from invokeai.backend.model_manager.configs.factory import AnyModelConfig, ModelConfigFactory +from invokeai.backend.model_manager.configs.identification_utils import InvalidMatchError, NotAMatchError +from invokeai.backend.model_manager.configs.main import Main_Checkpoint_QwenImage_Config +from invokeai.backend.model_manager.model_on_disk import ModelOnDisk +from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType +from tests.backend.flux.controlnet.instantx_flux_controlnet_state_dict import instantx_sd_shapes +from tests.backend.model_manager.load.state_dicts import ( + qwen_image_fun_controlnet_keys, + qwen_image_instantx_controlnet_keys, +) +from tests.backend.model_manager.load.state_dicts.utils import write_header_only_safetensors + +Keys = dict[str, tuple[list[int], str]] + +FUN_FILE_NAME = "Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors" +INSTANTX_FILE_NAME = "Qwen-Image-InstantX-ControlNet-Union.safetensors" + +_OVERRIDE_FIELDS: dict[str, object] = { + "hash": "blake3:fakehash", + "path": "/fake/models/controlnet.safetensors", + "file_size": 1000, + "name": "controlnet", + "description": "test", + "source": "test", + "source_type": "path", + "key": "test-key", +} + + +def _fun_keys() -> Keys: + return dict(qwen_image_fun_controlnet_keys.state_dict_keys) + + +def _instantx_keys() -> Keys: + return dict(qwen_image_instantx_controlnet_keys.state_dict_keys) + + +def _bf16(shapes: dict[str, list[int]]) -> Keys: + return {key: (shape, "BF16") for key, shape in shapes.items()} + + +# Sibling layouts with no captured header, reduced to the keys the probes read. +QWEN_IMAGE_2_1_FUN_KEYS = _bf16( + { + "control_img_in.weight": [4096, 129], + "control_img_in.bias": [4096], + "control_blocks.0.before_proj.weight": [4096, 4096], + "control_blocks.0.after_proj.weight": [4096, 4096], + "control_blocks.0.attn.to_q.weight": [4096, 4096], + "control_blocks.0.img_mlp.gate_layer.weight": [12288, 4096], + "control_blocks.0.img_mlp.proj.weight": [12288, 4096], + "control_blocks.0.img_mlp.out.weight": [4096, 12288], + "control_blocks.15.after_proj.weight": [4096, 4096], + } +) +FLUX2_FUN_KEYS = _bf16( + { + "control_img_in.weight": [6144, 260], + "control_img_in.bias": [6144], + "control_transformer_blocks.0.attn.to_q.weight": [6144, 6144], + "control_transformer_blocks.0.after_proj.weight": [6144, 6144], + } +) +Z_IMAGE_FUN_KEYS = _bf16( + { + "control_layers.0.attention.qkv.weight": [11520, 3840], + "control_layers.0.attention.out.weight": [3840, 3840], + "control_all_x_embedder.2-1.weight": [3840, 64], + "control_noise_refiner.0.attention.qkv.weight": [11520, 3840], + } +) +DIFFSYNTH_KEYS = _bf16( + { + "img_in.weight": [3072, 64], + "controlnet_blocks.0.input_proj.weight": [3072, 3072], + "controlnet_blocks.0.output_proj.weight": [3072, 3072], + "controlnet_blocks.0.x_rms.weight": [3072], + "controlnet_blocks.0.y_rms.weight": [3072], + } +) +# InstantX's FLUX.1 ControlNet-Union, diffusers layout: the same `controlnet_*` names over FLUX blocks. +FLUX_INSTANTX_KEYS = _bf16(instantx_sd_shapes) + + +def _write(tmp_path: Path, name: str, keys: Keys) -> Path: + return write_header_only_safetensors(tmp_path / name, keys) + + +def _instantx_inpainting_keys() -> Keys: + """InstantX's inpainting sibling: the control input also takes the 4 packed features of a mask.""" + return {**_instantx_keys(), "controlnet_x_embedder.weight": ([3072, 68], "BF16")} + + +@pytest.mark.parametrize( + ("name", "keys", "architecture"), + [(FUN_FILE_NAME, _fun_keys(), "fun_union"), (INSTANTX_FILE_NAME, _instantx_keys(), "instantx_union")], + ids=["fun", "instantx"], +) +def test_each_released_file_is_a_qwen_image_controlnet_of_its_design_and_nothing_else( + tmp_path: Path, name: str, keys: Keys, architecture: str +) -> None: + result = ModelConfigFactory.from_model_on_disk(_write(tmp_path, name, keys), allow_unknown=False) + + assert type(result.config) is ControlNet_Checkpoint_QwenImage_Config, result.details + assert result.match_count == 1, result.details + assert result.config.control_architecture == architecture + assert result.config.base is BaseModelType.QwenImage + assert result.config.type is ModelType.ControlNet + assert result.config.format is ModelFormat.Checkpoint + + +def test_the_flux_instantx_controlnet_is_still_a_flux_controlnet_and_not_a_qwen_image_one(tmp_path: Path) -> None: + path = _write(tmp_path, "FLUX.1-dev-Controlnet-Union.safetensors", FLUX_INSTANTX_KEYS) + + result = ModelConfigFactory.from_model_on_disk(path, allow_unknown=False) + + assert type(result.config) is ControlNet_Checkpoint_FLUX_Config, result.details + assert result.match_count == 1, result.details + with pytest.raises(NotAMatchError): + ControlNet_Checkpoint_QwenImage_Config.from_model_on_disk(ModelOnDisk(path), dict(_OVERRIDE_FIELDS)) + + +def test_the_instantx_inpainting_layout_is_refused_with_a_reason_rather_than_registered(tmp_path: Path) -> None: + """Recognised and unusable, so nothing is registered -- not even as an unknown model -- and the reason is the + installer's message.""" + result = ModelConfigFactory.from_model_on_disk( + _write(tmp_path, "Qwen-Image-InstantX-ControlNet-Inpainting.safetensors", _instantx_inpainting_keys()) + ) + + assert result.config is None + refusal = result.details[ControlNet_Checkpoint_QwenImage_Config.__name__] + assert isinstance(refusal, InvalidMatchError) + assert "does not support yet" in str(refusal) and "ControlNet Union instead" in str(refusal) + + +@pytest.mark.parametrize("prefix", ["", "model.diffusion_model."], ids=["bare", "comfyui-prefixed"]) +def test_the_qwen_image_main_probe_refuses_the_instantx_union(tmp_path: Path, prefix: str) -> None: + """The probe strips a ComfyUI prefix before it looks for the transformer's keys, so it has to before it looks + for the ControlNet's too, as the main loader does: otherwise a prefixed copy would be identified as a main + model, refused at load, and identified as one again by Re-identify.""" + keys = {f"{prefix}{name}": spec for name, spec in _instantx_keys().items()} + mod = ModelOnDisk(_write(tmp_path, INSTANTX_FILE_NAME, keys)) + + with pytest.raises(NotAMatchError): + Main_Checkpoint_QwenImage_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) + + +@pytest.mark.parametrize( + ("name", "preprocessor"), + [(FUN_FILE_NAME, None), ("Qwen-Image-Fun-Controlnet-Depth.safetensors", "depth_anything_image_processor")], + ids=["union", "depth"], +) +def test_the_preprocessor_is_chosen_from_the_name_as_for_every_controlnet( + tmp_path: Path, name: str, preprocessor: str | None +) -> None: + """A union adapter takes any control image, so none is pre-selected; a single-condition build picks its own.""" + config = ModelConfigFactory.from_model_on_disk(_write(tmp_path, name, _fun_keys()), allow_unknown=False).config + + assert isinstance(config, ControlNet_Checkpoint_QwenImage_Config) + assert config.default_settings is not None + assert config.default_settings.preprocessor == preprocessor + + +@pytest.mark.parametrize( + ("name", "keys"), [(FUN_FILE_NAME, _fun_keys()), (INSTANTX_FILE_NAME, _instantx_keys())], ids=["fun", "instantx"] +) +def test_a_stored_record_reads_back_as_the_same_qwen_image_controlnet(tmp_path: Path, name: str, keys: Keys) -> None: + """The record crosses the database and the API as a plain dict, so the config has to be a member of + `AnyModelConfig` under a discriminator of its own, and the design has to survive the round trip.""" + identified = ModelConfigFactory.from_model_on_disk(_write(tmp_path, name, keys), allow_unknown=False).config + assert identified is not None + + restored = TypeAdapter(AnyModelConfig).validate_python(identified.model_dump(mode="json")) + + assert type(restored) is ControlNet_Checkpoint_QwenImage_Config + assert restored.base is BaseModelType.QwenImage + assert restored.control_architecture == identified.control_architecture + + +def test_a_record_stored_before_the_design_was_recorded_reads_back_as_the_fun_union(tmp_path: Path) -> None: + """Every Qwen-Image ControlNet installed until now is a Fun-ControlNet: no other design was identified.""" + identified = ModelConfigFactory.from_model_on_disk( + _write(tmp_path, FUN_FILE_NAME, _fun_keys()), allow_unknown=False + ).config + assert identified is not None + stored = identified.model_dump(mode="json") + del stored["control_architecture"] + + restored = TypeAdapter(AnyModelConfig).validate_python(stored) + + assert type(restored) is ControlNet_Checkpoint_QwenImage_Config + assert restored.control_architecture == "fun_union" + + +@pytest.mark.parametrize( + ("name", "keys"), + [ + ("Qwen-Image-2.1-Fun-Controlnet-Union.safetensors", QWEN_IMAGE_2_1_FUN_KEYS), + ("FLUX.2-dev-Fun-Controlnet-Union.safetensors", FLUX2_FUN_KEYS), + ("Z-Image-Turbo-Fun-Controlnet-Union.safetensors", Z_IMAGE_FUN_KEYS), + ("Qwen-Image-DiffSynth-Controlnet.safetensors", DIFFSYNTH_KEYS), + ], + ids=["qwen_image_2_1_fun", "flux2_fun", "z_image_fun", "diffsynth"], +) +def test_the_other_control_designs_are_refused(tmp_path: Path, name: str, keys: Keys) -> None: + mod = ModelOnDisk(_write(tmp_path, name, keys)) + + with pytest.raises(NotAMatchError): + ControlNet_Checkpoint_QwenImage_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) + + +def _without_img_mod(keys: Keys) -> Keys: + return {key: value for key, value in keys.items() if ".img_mod." not in key} + + +def _with_control_img_in(keys: Keys, shape: list[int]) -> Keys: + return {**keys, "control_img_in.weight": (shape, "BF16")} + + +def _without(keys: Keys, key: str) -> Keys: + return {name: value for name, value in keys.items() if name != key} + + +@pytest.mark.parametrize( + "keys", + [ + _without_img_mod(_fun_keys()), + _with_control_img_in(_fun_keys(), [4096, 129]), + _without_img_mod(_instantx_keys()), + _without(_instantx_keys(), "txt_norm.weight"), + {**_instantx_keys(), "controlnet_x_embedder.weight": ([4096, 64], "BF16")}, + ], + ids=[ + "fun_single_stream_blocks", + "fun_wider_projection", + "instantx_single_stream_blocks", + "instantx_without_text_norm", + "instantx_wider_embedder", + ], +) +def test_a_controlnet_with_the_names_but_not_the_fingerprint_is_refused(tmp_path: Path, keys: Keys) -> None: + """Every part of a fingerprint carries weight: `control_blocks` at Qwen-Image's width without `img_mod` would be + a single-stream branch, `img_mod` behind a wider projection a branch for a wider base, and `controlnet_blocks` + without Qwen-Image's dual-stream block and text norm a FLUX ControlNet.""" + mod = ModelOnDisk(_write(tmp_path, FUN_FILE_NAME, keys)) + + with pytest.raises(NotAMatchError): + ControlNet_Checkpoint_QwenImage_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) diff --git a/tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py b/tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py deleted file mode 100644 index ccf0a3bb650..00000000000 --- a/tests/backend/model_manager/configs/test_qwen_image_fun_controlnet_config.py +++ /dev/null @@ -1,172 +0,0 @@ -"""Identification of alibaba-pai's Qwen-Image Fun-ControlNet-Union, through the config factory. - -The adapter is a VACE-style control branch: `control_img_in` projects 132 packed channels into Qwen-Image's -3072-wide stream, and five `control_blocks` copy the dual-stream `QwenImageTransformerBlock` with -`before_proj`/`after_proj` taps. Its siblings reuse the naming -- the Qwen-Image-2.1 branch is single-stream at -4096 wide, FLUX.2's keeps `control_transformer_blocks` at 6144 -- and the other Qwen-Image ControlNet designs -(InstantX, DiffSynth) share key families with FLUX ControlNets. So every case is a header written back without its -data: identification reads nothing else, and each config sees the real key names, shapes and dtypes. -""" - -from pathlib import Path - -import pytest -from pydantic import TypeAdapter - -from invokeai.backend.model_manager.configs.controlnet import ControlNet_Checkpoint_QwenImage_Config -from invokeai.backend.model_manager.configs.factory import AnyModelConfig, ModelConfigFactory -from invokeai.backend.model_manager.configs.identification_utils import NotAMatchError -from invokeai.backend.model_manager.model_on_disk import ModelOnDisk -from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelFormat, ModelType -from tests.backend.model_manager.load.state_dicts import ( - qwen_image_fun_controlnet_keys, - qwen_image_instantx_controlnet_keys, -) -from tests.backend.model_manager.load.state_dicts.utils import write_header_only_safetensors - -Keys = dict[str, tuple[list[int], str]] - -FUN_FILE_NAME = "Qwen-Image-2512-Fun-Controlnet-Union-2602.safetensors" - -_OVERRIDE_FIELDS: dict[str, object] = { - "hash": "blake3:fakehash", - "path": "/fake/models/controlnet.safetensors", - "file_size": 1000, - "name": "controlnet", - "description": "test", - "source": "test", - "source_type": "path", - "key": "test-key", -} - - -def _fun_keys() -> Keys: - return dict(qwen_image_fun_controlnet_keys.state_dict_keys) - - -def _bf16(shapes: dict[str, list[int]]) -> Keys: - return {key: (shape, "BF16") for key, shape in shapes.items()} - - -# Sibling layouts with no captured header, reduced to the keys the probes read. -QWEN_IMAGE_2_1_FUN_KEYS = _bf16( - { - "control_img_in.weight": [4096, 129], - "control_img_in.bias": [4096], - "control_blocks.0.before_proj.weight": [4096, 4096], - "control_blocks.0.after_proj.weight": [4096, 4096], - "control_blocks.0.attn.to_q.weight": [4096, 4096], - "control_blocks.0.img_mlp.gate_layer.weight": [12288, 4096], - "control_blocks.0.img_mlp.proj.weight": [12288, 4096], - "control_blocks.0.img_mlp.out.weight": [4096, 12288], - "control_blocks.15.after_proj.weight": [4096, 4096], - } -) -FLUX2_FUN_KEYS = _bf16( - { - "control_img_in.weight": [6144, 260], - "control_img_in.bias": [6144], - "control_transformer_blocks.0.attn.to_q.weight": [6144, 6144], - "control_transformer_blocks.0.after_proj.weight": [6144, 6144], - } -) -Z_IMAGE_FUN_KEYS = _bf16( - { - "control_layers.0.attention.qkv.weight": [11520, 3840], - "control_layers.0.attention.out.weight": [3840, 3840], - "control_all_x_embedder.2-1.weight": [3840, 64], - "control_noise_refiner.0.attention.qkv.weight": [11520, 3840], - } -) -DIFFSYNTH_KEYS = _bf16( - { - "img_in.weight": [3072, 64], - "controlnet_blocks.0.input_proj.weight": [3072, 3072], - "controlnet_blocks.0.output_proj.weight": [3072, 3072], - "controlnet_blocks.0.x_rms.weight": [3072], - "controlnet_blocks.0.y_rms.weight": [3072], - } -) - - -def _write(tmp_path: Path, name: str, keys: Keys) -> Path: - return write_header_only_safetensors(tmp_path / name, keys) - - -def test_the_released_file_is_a_qwen_image_controlnet_and_nothing_else(tmp_path: Path) -> None: - result = ModelConfigFactory.from_model_on_disk(_write(tmp_path, FUN_FILE_NAME, _fun_keys()), allow_unknown=False) - - assert type(result.config) is ControlNet_Checkpoint_QwenImage_Config, result.details - assert result.match_count == 1, result.details - assert result.config.base is BaseModelType.QwenImage - assert result.config.type is ModelType.ControlNet - assert result.config.format is ModelFormat.Checkpoint - - -@pytest.mark.parametrize( - ("name", "preprocessor"), - [(FUN_FILE_NAME, None), ("Qwen-Image-Fun-Controlnet-Depth.safetensors", "depth_anything_image_processor")], - ids=["union", "depth"], -) -def test_the_preprocessor_is_chosen_from_the_name_as_for_every_controlnet( - tmp_path: Path, name: str, preprocessor: str | None -) -> None: - """A union adapter takes any control image, so none is pre-selected; a single-condition build picks its own.""" - config = ModelConfigFactory.from_model_on_disk(_write(tmp_path, name, _fun_keys()), allow_unknown=False).config - - assert isinstance(config, ControlNet_Checkpoint_QwenImage_Config) - assert config.default_settings is not None - assert config.default_settings.preprocessor == preprocessor - - -def test_a_stored_record_reads_back_as_a_qwen_image_controlnet(tmp_path: Path) -> None: - """The record crosses the database and the API as a plain dict, so the config has to be a member of - `AnyModelConfig` under a discriminator of its own.""" - stored = ModelConfigFactory.from_model_on_disk( - _write(tmp_path, FUN_FILE_NAME, _fun_keys()), allow_unknown=False - ).config.model_dump(mode="json") - - restored = TypeAdapter(AnyModelConfig).validate_python(stored) - - assert type(restored) is ControlNet_Checkpoint_QwenImage_Config - assert restored.base is BaseModelType.QwenImage - - -@pytest.mark.parametrize( - ("name", "keys"), - [ - ("Qwen-Image-2.1-Fun-Controlnet-Union.safetensors", QWEN_IMAGE_2_1_FUN_KEYS), - ("FLUX.2-dev-Fun-Controlnet-Union.safetensors", FLUX2_FUN_KEYS), - ("Z-Image-Turbo-Fun-Controlnet-Union.safetensors", Z_IMAGE_FUN_KEYS), - ("Qwen-Image-InstantX-ControlNet-Union.safetensors", dict(qwen_image_instantx_controlnet_keys.state_dict_keys)), - ("Qwen-Image-DiffSynth-Controlnet.safetensors", DIFFSYNTH_KEYS), - ], - ids=["qwen_image_2_1_fun", "flux2_fun", "z_image_fun", "instantx", "diffsynth"], -) -def test_the_other_control_designs_are_refused(tmp_path: Path, name: str, keys: Keys) -> None: - mod = ModelOnDisk(_write(tmp_path, name, keys)) - - with pytest.raises(NotAMatchError): - ControlNet_Checkpoint_QwenImage_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) - - -def _without_img_mod(keys: Keys) -> Keys: - return {key: value for key, value in keys.items() if ".img_mod." not in key} - - -def _with_control_img_in(keys: Keys, shape: list[int]) -> Keys: - return {**keys, "control_img_in.weight": (shape, "BF16")} - - -@pytest.mark.parametrize( - "keys", - [_without_img_mod(_fun_keys()), _with_control_img_in(_fun_keys(), [4096, 129])], - ids=["single_stream_blocks", "wider_projection"], -) -def test_a_branch_with_the_names_but_not_the_fingerprint_is_refused(tmp_path: Path, keys: Keys) -> None: - """Both halves of the fingerprint carry weight: `control_blocks` at Qwen-Image's width without `img_mod` - would be a single-stream branch, and `img_mod` behind a wider projection a branch for a wider base.""" - mod = ModelOnDisk(_write(tmp_path, FUN_FILE_NAME, keys)) - - with pytest.raises(NotAMatchError): - ControlNet_Checkpoint_QwenImage_Config.from_model_on_disk(mod, dict(_OVERRIDE_FIELDS)) diff --git a/tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py b/tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py index ac6d5eb68b5..3f3ff708834 100644 --- a/tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py +++ b/tests/backend/model_manager/load/state_dicts/qwen_image_instantx_controlnet_keys.py @@ -10,8 +10,8 @@ A different design from the Fun branch: a trimmed copy of the Qwen-Image transformer itself (`img_in`, `txt_in` at Qwen2.5-VL's 3584 width, `txt_norm`, `time_text_embed`, `transformer_blocks.N`) with `controlnet_x_embedder` for the control latent and one `controlnet_blocks.N` output projection per block -- -the key family InstantX's FLUX ControlNets use. It has no `control_img_in`, which is what keeps it out of -the Qwen-Image Fun config. +the key family InstantX's FLUX ControlNets use, which is why the FLUX probe has to refuse it. The full file +has five of each stack. """ state_dict_keys: dict[str, tuple[list[int], str]] = { diff --git a/tests/backend/model_manager/load/test_fun_controlnet_loader.py b/tests/backend/model_manager/load/test_fun_controlnet_loader.py deleted file mode 100644 index b4e4ac5a731..00000000000 --- a/tests/backend/model_manager/load/test_fun_controlnet_loader.py +++ /dev/null @@ -1,98 +0,0 @@ -"""What the Qwen-Image Fun-ControlNet loader makes of a checkpoint: the geometry it reads off the tensors, the dtype -it casts to, and the quantized files it refuses rather than loads unscaled. - -Like the Z-Image ControlNet loader it builds under `init_empty_weights` and assigns the file's tensors, so an fp8 -weight with its scale dropped would become the parameter as it is (`test_z_image_control_adapter_loader.py`). No -quantized build of this adapter is published (alibaba-pai ships two dense bf16 files), so refusing costs nothing. -""" - -from pathlib import Path - -import pytest -import torch - -from invokeai.backend.fun_controlnet.qwen_image import QWEN_IMAGE_FUN_CONTROL_LAYERS, QwenImageFunControlBranch -from invokeai.backend.model_manager.configs.controlnet import ControlNet_Checkpoint_QwenImage_Config -from invokeai.backend.model_manager.load.model_loaders import fun_controlnet -from invokeai.backend.model_manager.load.model_loaders.fun_controlnet import QwenImageFunControlNetLoader -from tests.fixtures.loader_seams import Seam, prepare -from tests.fixtures.quantized_payloads import comfy_quant_marker, quantize_convrot, quantize_scaled_fp8 - -# One 128-wide head: the narrowest branch the loader's head rule accepts, with the real five-block layout. -HIDDEN = 128 -QUANTIZED_LAYER = "control_blocks.0.attn.to_q" - -SEAM = Seam( - loader=QwenImageFunControlNetLoader, - module=fun_controlnet, - entry="_load_model", - compute_dtype=torch.bfloat16, - # The loader takes its dtype from the device and never reads `self._torch_dtype`. - patches_device=True, - sets_torch_dtype=False, - casts_fp8_storage=False, -) - - -def _checkpoint() -> dict[str, torch.Tensor]: - """A float32 file with the real layout; the loader has to cast it.""" - torch.manual_seed(0) - branch = QwenImageFunControlBranch(hidden_size=HIDDEN, num_attention_heads=1, attention_head_dim=128) - return {name: tensor.detach().clone() for name, tensor in branch.state_dict().items()} - - -def _driver(monkeypatch: pytest.MonkeyPatch, tmp_path: Path, state_dict: dict[str, torch.Tensor]): - checkpoint = tmp_path / "qwen_image_fun_controlnet.safetensors" - checkpoint.touch() - config = ControlNet_Checkpoint_QwenImage_Config.model_construct(path=str(checkpoint), name="qwen-image-control") - return prepare(SEAM, monkeypatch, state_dict=state_dict), config - - -def test_a_dense_checkpoint_loads_with_its_geometry_in_the_compute_dtype(monkeypatch, tmp_path) -> None: - run, config = _driver(monkeypatch, tmp_path, _checkpoint()) - - model = run.load(config) - - assert isinstance(model, QwenImageFunControlBranch) - assert model.control_layers == QWEN_IMAGE_FUN_CONTROL_LAYERS - assert (model.hidden_size, model.control_in_dim, model.control_blocks[0].attn.heads) == (HIDDEN, 132, 1) - assert {parameter.dtype for parameter in model.parameters()} == {torch.bfloat16} - assert not model.training - - -def test_a_scaled_fp8_checkpoint_is_refused_rather_than_loaded_unscaled(monkeypatch, tmp_path) -> None: - payload = quantize_scaled_fp8(torch.randn(HIDDEN, HIDDEN)) - state_dict = _checkpoint() - state_dict[f"{QUANTIZED_LAYER}.weight"] = payload.codes - state_dict[f"{QUANTIZED_LAYER}.weight_scale"] = payload.scale - run, config = _driver(monkeypatch, tmp_path, state_dict) - - with pytest.raises(ValueError, match="quantization side channel"): - run.load(config) - - -def test_an_int8_checkpoint_is_refused_by_its_marker(monkeypatch, tmp_path) -> None: - codes, scale, _ = quantize_convrot(torch.randn(HIDDEN, 256)) - state_dict = _checkpoint() - state_dict[f"{QUANTIZED_LAYER}.weight"] = codes - state_dict[f"{QUANTIZED_LAYER}.weight_scale"] = scale - state_dict[f"{QUANTIZED_LAYER}.comfy_quant"] = comfy_quant_marker({"format": "int8_tensorwise", "convrot": True}) - run, config = _driver(monkeypatch, tmp_path, state_dict) - - with pytest.raises(ValueError, match="quantization side channel"): - run.load(config) - - -@pytest.mark.parametrize( - ("rewrite", "message"), - [ - (lambda sd: {k: v for k, v in sd.items() if not k.startswith("control_blocks.4.")}, "4 control blocks"), - (lambda sd: {**sd, "control_img_in.weight": torch.zeros(HIDDEN, 64)}, "takes 64"), - ], - ids=["four-blocks", "sixteen-channel-context"], -) -def test_another_recipe_is_refused_by_name(monkeypatch, tmp_path, rewrite, message) -> None: - run, config = _driver(monkeypatch, tmp_path, rewrite(_checkpoint())) - - with pytest.raises(ValueError, match=message): - run.load(config) diff --git a/tests/backend/model_manager/load/test_qwen_image_controlnet_loader.py b/tests/backend/model_manager/load/test_qwen_image_controlnet_loader.py new file mode 100644 index 00000000000..5b9248fdd60 --- /dev/null +++ b/tests/backend/model_manager/load/test_qwen_image_controlnet_loader.py @@ -0,0 +1,248 @@ +"""What the Qwen-Image ControlNet loader makes of a checkpoint: which design it builds (the one the record names), the +geometry it reads off the tensors, the dtype it casts to, and the files it refuses rather than loads wrongly. + +Both designs build under `init_empty_weights` and assign the file's tensors, so an fp8 weight with its scale dropped +would become the parameter as it is (`test_z_image_control_adapter_loader.py`). No quantized build of either is +published (alibaba-pai and Comfy-Org ship dense bf16 files), so refusing costs nothing. +""" + +from pathlib import Path + +import pytest +import safetensors.torch +import torch +from diffusers.models.controlnets.controlnet_qwenimage import QwenImageControlNetModel + +from invokeai.backend.fun_controlnet.qwen_image import QWEN_IMAGE_FUN_CONTROL_LAYERS, QwenImageFunControlBranch +from invokeai.backend.model_manager.configs.controlnet import ControlNet_Checkpoint_QwenImage_Config +from invokeai.backend.model_manager.configs.main import Main_Checkpoint_QwenImage_Config +from invokeai.backend.model_manager.load.model_loaders import qwen_image, qwen_image_controlnet +from invokeai.backend.model_manager.load.model_loaders.qwen_image import QwenImageCheckpointModel +from invokeai.backend.model_manager.load.model_loaders.qwen_image_controlnet import ( + QWEN_IMAGE_AXES_DIMS_ROPE, + QwenImageControlNetLoader, +) +from tests.backend.model_manager.load.state_dicts.qwen_image_instantx_controlnet_keys import state_dict_keys +from tests.fixtures.loader_seams import Seam, prepare +from tests.fixtures.quantized_payloads import comfy_quant_marker, quantize_convrot, quantize_scaled_fp8 + +# One 128-wide head: the narrowest ControlNet the loaders' head rule accepts, with the real five-block layouts. +HIDDEN = 128 +QUANTIZED_LAYER = "control_blocks.0.attn.to_q" +INSTANTX_BLOCKS = 5 +INSTANTX_TEXT_DIM = 24 + +SEAM = Seam( + loader=QwenImageControlNetLoader, + module=qwen_image_controlnet, + entry="_load_model", + compute_dtype=torch.bfloat16, + # The loader takes its dtype from the device and never reads `self._torch_dtype`. + patches_device=True, + sets_torch_dtype=False, + casts_fp8_storage=False, +) + + +def _checkpoint() -> dict[str, torch.Tensor]: + """A float32 Fun-ControlNet file with the real layout; the loader has to cast it.""" + torch.manual_seed(0) + branch = QwenImageFunControlBranch(hidden_size=HIDDEN, num_attention_heads=1, attention_head_dim=128) + return {name: tensor.detach().clone() for name, tensor in branch.state_dict().items()} + + +def _instantx_checkpoint() -> dict[str, torch.Tensor]: + """A float32 InstantX file: diffusers' model at one 128-wide head, with every tensor random so a load that + dropped or swapped one shows.""" + torch.manual_seed(1) + model = QwenImageControlNetModel( + num_layers=INSTANTX_BLOCKS, + attention_head_dim=128, + num_attention_heads=1, + joint_attention_dim=INSTANTX_TEXT_DIM, + axes_dims_rope=QWEN_IMAGE_AXES_DIMS_ROPE, + ) + return {name: torch.randn_like(tensor) for name, tensor in model.state_dict().items()} + + +def _driver(monkeypatch: pytest.MonkeyPatch, tmp_path: Path, state_dict: dict[str, torch.Tensor], **record): + checkpoint = tmp_path / "qwen_image_controlnet.safetensors" + checkpoint.touch() + config = ControlNet_Checkpoint_QwenImage_Config.model_construct( + path=str(checkpoint), name="qwen-image-control", **record + ) + return prepare(SEAM, monkeypatch, state_dict=state_dict), config + + +def test_a_record_without_a_design_loads_the_fun_branch_with_its_geometry_in_the_compute_dtype( + monkeypatch, tmp_path +) -> None: + run, config = _driver(monkeypatch, tmp_path, _checkpoint()) + + model = run.load(config) + + assert isinstance(model, QwenImageFunControlBranch) + assert model.control_layers == QWEN_IMAGE_FUN_CONTROL_LAYERS + assert (model.hidden_size, model.control_in_dim, model.control_blocks[0].attn.heads) == (HIDDEN, 132, 1) + assert {parameter.dtype for parameter in model.parameters()} == {torch.bfloat16} + assert not model.training + + +def test_an_instantx_record_loads_every_tensor_into_the_controlnet_its_keys_describe(monkeypatch, tmp_path) -> None: + checkpoint = _instantx_checkpoint() + run, config = _driver(monkeypatch, tmp_path, checkpoint, control_architecture="instantx_union") + + model = run.load(config) + + assert isinstance(model, QwenImageControlNetModel) + assert (len(model.transformer_blocks), len(model.controlnet_blocks)) == (INSTANTX_BLOCKS, INSTANTX_BLOCKS) + assert (model.inner_dim, model.transformer_blocks[0].attn.heads) == (HIDDEN, 1) + assert (model.config.joint_attention_dim, model.config.in_channels) == (INSTANTX_TEXT_DIM, 64) + assert model.config.extra_condition_channels == 0 + assert not model.training + loaded = model.state_dict() + assert loaded.keys() == checkpoint.keys() + for name, tensor in checkpoint.items(): + assert torch.equal(loaded[name], tensor.to(torch.bfloat16)), name + + +def test_the_released_instantx_header_loads_strictly_into_the_controlnet_built_from_it(monkeypatch, tmp_path) -> None: + """The captured header widened to the file's five blocks (its 181 tensors), on the meta device so nothing of the + 3.5 GB is allocated: every name and shape lands, and the geometry is Qwen-Image's.""" + full = { + name.replace(".0.", f".{index}.", 1): spec + for name, spec in state_dict_keys.items() + for index in ( + range(INSTANTX_BLOCKS) if name.startswith(("transformer_blocks.0.", "controlnet_blocks.0.")) else [0] + ) + } + assert len(full) == 181 + with torch.device("meta"): + checkpoint = {name: torch.empty(shape, dtype=torch.bfloat16) for name, (shape, _dtype) in full.items()} + run, config = _driver(monkeypatch, tmp_path, checkpoint, control_architecture="instantx_union") + + model = run.load(config) + + assert isinstance(model, QwenImageControlNetModel) + assert {name: list(tensor.shape) for name, tensor in model.state_dict().items()} == { + name: shape for name, (shape, _dtype) in full.items() + } + assert (model.config.num_layers, model.config.num_attention_heads, model.config.joint_attention_dim) == ( + 5, + 24, + 3584, + ) + + +def test_the_record_decides_the_design_and_a_wrong_one_fails_by_name(monkeypatch, tmp_path) -> None: + run, config = _driver(monkeypatch, tmp_path, _instantx_checkpoint(), control_architecture="fun_union") + with pytest.raises(ValueError, match="control_img_in.weight"): + run.load(config) + + run, config = _driver(monkeypatch, tmp_path, _checkpoint(), control_architecture="instantx_union") + with pytest.raises(ValueError, match="Not an InstantX Qwen Image ControlNet"): + run.load(config) + + +def test_the_instantx_inpainting_layout_is_refused_by_name(monkeypatch, tmp_path) -> None: + checkpoint = _instantx_checkpoint() + checkpoint["controlnet_x_embedder.weight"] = torch.zeros(HIDDEN, 68) + run, config = _driver(monkeypatch, tmp_path, checkpoint, control_architecture="instantx_union") + + with pytest.raises(ValueError, match="inpainting layout"): + run.load(config) + + +@pytest.mark.parametrize( + ("rewrite", "message"), + [ + (lambda sd: {k: v for k, v in sd.items() if not k.startswith("transformer_blocks.4.")}, "missing"), + (lambda sd: {**sd, "controlnet_blocks.5.weight": torch.zeros(HIDDEN, HIDDEN)}, "missing"), + (lambda sd: {**sd, "pos_embed_input.weight": torch.zeros(HIDDEN, 64)}, "unexpected"), + (lambda sd: {**sd, "transformer_blocks.0.attn.norm_q.weight": torch.zeros(64)}, "attention heads"), + ], + ids=["fewer-blocks-than-projections", "more-projections-than-blocks", "stray-key", "other-head-width"], +) +def test_an_instantx_checkpoint_that_is_not_the_layout_is_refused(monkeypatch, tmp_path, rewrite, message) -> None: + run, config = _driver(monkeypatch, tmp_path, rewrite(_instantx_checkpoint()), control_architecture="instantx_union") + + with pytest.raises(ValueError, match=message): + run.load(config) + + +@pytest.mark.parametrize( + ("checkpoint", "layer", "architecture"), + [ + (_checkpoint, QUANTIZED_LAYER, "fun_union"), + (_instantx_checkpoint, "transformer_blocks.0.attn.to_q", "instantx_union"), + ], + ids=["fun", "instantx"], +) +def test_a_scaled_fp8_checkpoint_is_refused_rather_than_loaded_unscaled( + monkeypatch, tmp_path, checkpoint, layer, architecture +) -> None: + payload = quantize_scaled_fp8(torch.randn(HIDDEN, HIDDEN)) + state_dict = checkpoint() + state_dict[f"{layer}.weight"] = payload.codes + state_dict[f"{layer}.weight_scale"] = payload.scale + run, config = _driver(monkeypatch, tmp_path, state_dict, control_architecture=architecture) + + with pytest.raises(ValueError, match="quantization side channel"): + run.load(config) + + +def test_an_int8_checkpoint_is_refused_by_its_marker(monkeypatch, tmp_path) -> None: + codes, scale, _ = quantize_convrot(torch.randn(HIDDEN, 256)) + state_dict = _checkpoint() + state_dict[f"{QUANTIZED_LAYER}.weight"] = codes + state_dict[f"{QUANTIZED_LAYER}.weight_scale"] = scale + state_dict[f"{QUANTIZED_LAYER}.comfy_quant"] = comfy_quant_marker({"format": "int8_tensorwise", "convrot": True}) + run, config = _driver(monkeypatch, tmp_path, state_dict) + + with pytest.raises(ValueError, match="quantization side channel"): + run.load(config) + + +@pytest.mark.parametrize( + ("rewrite", "message"), + [ + (lambda sd: {k: v for k, v in sd.items() if not k.startswith("control_blocks.4.")}, "4 control blocks"), + (lambda sd: {**sd, "control_img_in.weight": torch.zeros(HIDDEN, 64)}, "takes 64"), + ], + ids=["four-blocks", "sixteen-channel-context"], +) +def test_another_fun_recipe_is_refused_by_name(monkeypatch, tmp_path, rewrite, message) -> None: + run, config = _driver(monkeypatch, tmp_path, rewrite(_checkpoint())) + + with pytest.raises(ValueError, match=message): + run.load(config) + + +def test_an_instantx_file_an_earlier_version_recorded_as_a_main_model_is_refused_with_the_fix( + monkeypatch, tmp_path +) -> None: + """Earlier versions identified the InstantX union as a Qwen Image main model, and such records outlive the fix + to identification: loading one as a transformer says what it is and how to repair the record, before any room + is reserved for a transformer that cannot be built.""" + with torch.device("meta"): + checkpoint = { + name: torch.empty(shape, dtype=torch.bfloat16) for name, (shape, _dtype) in state_dict_keys.items() + } + path = tmp_path / "Qwen-Image-InstantX-ControlNet-Union.safetensors" + path.touch() + seam = Seam( + loader=QwenImageCheckpointModel, + module=qwen_image, + entry="_load_from_singlefile", + load_file_host=safetensors.torch, + compute_dtype=torch.bfloat16, + patches_device=True, + sets_torch_dtype=False, + casts_fp8_storage=False, + ) + run = prepare(seam, monkeypatch, state_dict=checkpoint, metadata=None) + + with pytest.raises(ValueError, match="is a Qwen Image ControlNet, not a main model.*Re-identify"): + run.load(Main_Checkpoint_QwenImage_Config.model_construct(path=str(path), name="qwen-instantx")) + + assert run.reserved == [] diff --git a/tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/Qwen-Image-InstantX-ControlNet-Union.safetensors b/tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/Qwen-Image-InstantX-ControlNet-Union.safetensors new file mode 100644 index 00000000000..057eb1a2f79 --- /dev/null +++ b/tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/Qwen-Image-InstantX-ControlNet-Union.safetensors @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:073abb19a85ac86b267e6865d6bd51ea11359cfc8d3788b066b0761e257ed28d +size 27457 diff --git a/tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/__test_metadata__.json b/tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/__test_metadata__.json new file mode 100644 index 00000000000..beac4aadea6 --- /dev/null +++ b/tests/model_identification/stripped_models/10359709-71d3-4f27-9761-c975cd47cfb7/__test_metadata__.json @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf049fe66e4cd5367fdaaa8950c7a2310759d6b999d006cff56ce98ec64bc958 +size 685